莫比乌斯反演学习笔记
概念
莫比乌斯函数 μ(n)\mu(n)μ(n),是一个积性函数,定义为:
μ(n)={1,n=10,nisdivisiblebythesquareofaprimenumber(−1)k,kisthenumberofprimefactorsofn\mu(n)=\begin{cases}1,n=1\\ 0,n\;is\;divisible\;by\;the\;square\;of\;a\;prime\;number\\ (-1)^k,k\;is\;the\;number\;of\;prime\;factors\;of\;n \end{cases}μ(n)=⎩⎨⎧1,n=10,nisdivisiblebythesquareofaprimenumber(−1)k,kisthenumberofprimefactorsofn
其性质有:一、∑d∣nμ(d)=[n=1]\sum_{d|n}\mu(d)=[n=1]∑d∣nμ(d)=[n=1];二、μ∗1=ϵ\mu*1=\epsilonμ∗1=ϵ,其中 ∗*∗ 表示狄利克雷卷积,ϵ=[n=1]\epsilon=[n=1]ϵ=[n=1](其实这条与一等价)
莫比乌斯反演的形式有二:一、设 F(n)=∑n∣mf(m)F(n)=\sum_{n|m}f(m)F(n)=∑n∣mf(m),有 f(n)=∑n∣mF(m)μ(mn)f(n)=\sum_{n|m}F(m)\mu(\frac{m}{n})f(n)=∑n∣mF(m)μ(nm);二、设 F(n)=∑m∣nf(m)F(n)=\sum_{m|n}f(m)F(n)=∑m∣nf(m),有 f(n)=∑m∣nF(nm)μ(m)=∑m∣nF(m)μ(nm)f(n)=\sum_{m|n}F(\frac{n}{m})\mu(m)=\sum_{m|n}F(m)\mu(\frac{n}{m})f(n)=∑m∣nF(mn)μ(m)=∑m∣nF(m)μ(mn);
例题
1. Luogu P2257 YY的GCD
题意
给定 N,MN, MN,M,求 1≤x≤n1 \leq x \leq n1≤x≤n,1≤y≤m1 \leq y \leq m1≤y≤m 且 gcd(x,y)\gcd(x, y)gcd(x,y) 为质数的 (x,y)(x, y)(x,y) 有多少对。
T=104;n,m≤107T = 10^4;\;n, m \leq 10^7T=104;n,m≤107。
做法
设 f(p)=∑x=1n∑y=1m[gcd(x,y)=p];F(p)=∑p∣qf(q)=⌊np⌋⌊mp⌋;L=min(n,m)f(p)=\sum_{x=1}^n\sum_{y=1}^m[\gcd(x, y)=p]; F(p)=\sum_{p|q}f(q)=\lfloor\frac{n}{p}\rfloor\lfloor\frac{m}{p}\rfloor; L=\min(n,m)f(p)=∑x=1n∑y=1m[gcd(x,y)=p];F(p)=∑p∣qf(q)=⌊pn⌋⌊pm⌋;L=min(n,m)。
即求:
∑p∈Primef(p)=∑p∈Prime∑p∣xF(x)μ(xp)=∑p∈Prime∑i=1L/p⌊nip⌋⌊mip⌋μ(i)=∑T=1L⌊nT⌋⌊mT⌋∑p∣T&p∈Primeμ(Tp)\sum_{p\in Prime}f(p)\\ =\sum_{p\in Prime}\sum_{p|x}F(x)\mu(\frac{x}{p})\\ =\sum_{p\in Prime}\sum_{i=1}^{L/p}\lfloor\frac{n}{ip}\rfloor\lfloor\frac{m}{ip}\rfloor\mu(i)\\ =\sum_{T=1}^{L}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{p|T\;\&\;p\in Prime}\mu(\frac{T}{p})p∈Prime∑f(p)=p∈Prime∑p∣x∑F(x)μ(px)=p∈Prime∑i=1∑L/p⌊ipn⌋⌊ipm⌋μ(i)=T=1∑L⌊Tn⌋⌊Tm⌋p∣T&p∈Prime∑μ(pT)
重点在于求 g(x)≜∑p∣x&p∈Primeμ(xp)g(x)\triangleq\sum_{p|x\;\&\;p\in Prime}\mu(\frac{x}{p})g(x)≜∑p∣x&p∈Primeμ(px)。ppp 是 xxx 的一个质因数,考虑通过某种顺序枚举 xxx 的质因数,发现线性筛的过程会将 xxx 拆成一个最小的质因数和另一个数的乘积,即 x=y⋅p,p∈Primex=y\cdot p,\;p\in Primex=y⋅p,p∈Prime,则有:
g(x)={μ(1),x∈Primeg(y),pisafactorofy−g(y)+μ(y),pisnotafactorofyg(x)=\begin{cases}\mu(1),\;x\in Prime\\ g(y),\;p\;is\;a\;factor\;of\;y\\ -g(y)+\mu(y),\;p\;is\;not\;a\;factor\;of\;y\;\end{cases}g(x)=⎩⎨⎧μ(1),x∈Primeg(y),pisafactorofy−g(y)+μ(y),pisnotafactorofy
需要注意从 −g(y)-g(y)−g(y) 转移因为 g(y)g(y)g(y) 所包含的 μ\muμ 与 g(x)g(x)g(x) 所包含的 μ\muμ 差一个因子 ppp。
代码
#include <bits/stdc++.h>const int N = 1e7;int mu[N + 2], prime[N + 2], top, sum[N + 2];
bool nprime[N + 2];void solve() {int n, m;std::cin >> n >> m;long long ans = 0;for (int l = 1, r; l <= std::min(n, m); l = r + 1) {r = std::min(n / (n / l), m / (m / l));ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);}std::cout << ans << '\n';
}int main() {std::ios::sync_with_stdio(0);std::cin.tie(0);std::cout.tie(0);mu[1] = 1;for (int i = 2; i <= N; i++) {if (!nprime[i]) {prime[++top] = i;mu[i] = -1;sum[i] = 1;}for (int j = 1; j <= top && 1ll * i * prime[j] <= N; j++) {int now = i * prime[j];nprime[now] = 1;if (i % prime[j] == 0) {mu[now] = 0;sum[now] = mu[i];break;}mu[now] = -mu[i];sum[now] = mu[i] - sum[i];}}for (int i = 1; i <= N; i++) {sum[i] += sum[i - 1];}int t;std::cin >> t;while (t--) {solve();}
}
2. Luogu P2522 [HAOI2011] Problem b
题意
对于给出的 nnn 个询问,每次求有多少个数对 (x,y)(x,y)(x,y),满足 a≤x≤ba \le x \le ba≤x≤b,c≤y≤dc \le y \le dc≤y≤d,且 gcd(x,y)=k\gcd(x,y) = kgcd(x,y)=k。
1≤n,k≤5×1041 \le n,k \le 5 \times 10^41≤n,k≤5×104,1≤a≤b≤5×1041 \le a \le b \le 5 \times 10^41≤a≤b≤5×104,1≤c≤d≤5×1041 \le c \le d \le 5 \times 10^41≤c≤d≤5×104。
做法
(这个感觉比上面一个更加板子)
可以 a′←⌈ak⌉,b′←⌊bk⌋a'\gets\lceil\frac{a}{k}\rceil,\;b'\gets\lfloor\frac{b}{k}\rfloora′←⌈ka⌉,b′←⌊kb⌋ 这样操作把 kkk 转换为 111,然后对于两个区间可以容斥为 res(b′,d′)−res(a′−1,d′)−res(b′,c′−1)+res(a′−1,c′−1)res(b',d')-res(a'-1,d')-res(b',c'-1)+res(a'-1,c'-1)res(b′,d′)−res(a′−1,d′)−res(b′,c′−1)+res(a′−1,c′−1)。即求 ∑x=1n∑y=1m[gcd(x,y)=1]=∑i=1min(n,m)⌊ni⌋⌊mi⌋μ(i)\sum_{x=1}^{n}\sum_{y=1}^{m}{[\gcd(x,y)=1]}=\sum_{i=1}^{\min(n,m)}\lfloor\frac{n}{i}\rfloor\lfloor\frac{m}{i}\rfloor\mu(i)∑x=1n∑y=1m[gcd(x,y)=1]=∑i=1min(n,m)⌊in⌋⌊im⌋μ(i)。
代码
#include <bits/stdc++.h>const int N = 5e4;int mu[N + 2], prime[N + 2], top, sum[N + 2];
bool nprime[N + 2];long long work(int n, int m) {long long ans = 0;if (n > m) {std::swap(n, m);}for (int l = 1, r; l <= n; l = r + 1) {r = std::min(n / (n / l), m / (m / l));ans += 1ll * (n / l) * (m / l) * (sum[r] - sum[l - 1]);}return ans;
}void solve() {int a, b, c, d, k;std::cin >> a >> b >> c >> d >> k;a = (a + k - 1) / k;c = (c + k - 1) / k;b = b / k;d = d / k;std::cout << (work(b, d) - work(a - 1, d) - work(b, c - 1) + work(a - 1, c - 1)) << '\n';
}int main() {std::ios::sync_with_stdio(0);std::cin.tie(0);std::cout.tie(0);mu[1] = 1;for (int i = 2; i <= N; i++) {if (!nprime[i]) {prime[++top] = i;mu[i] = -1;}for (int j = 1; j <= top && 1ll * i * prime[j] <= N; j++) {int now = i * prime[j];nprime[now] = 1;if (i % prime[j] == 0) {mu[now] = 0;break;}mu[now] = -mu[i];}}for (int i = 1; i <= N; i++) {sum[i] = sum[i - 1] + mu[i];}int t;std::cin >> t;while (t--) {solve();}
}