莫比乌斯相关
莫比乌斯相关
莫比乌斯函数
定义
性质
Dirichlet 卷积相关
平方相关
证明:考虑若 μ(i)2=1,则右侧只有一项 j=1(因为 i 无平方因子)否则说明其至少有一个质因子 p 出现了两次以上。
考虑将所有 j2∣i 分成两类:p 是 j 的因子/不是 j 的因子(由于 μ(j) 不能为 0,因此 p 至多出现一次)。则两类 j 之间建立起一一对应关系,且对于每一对,它们的 μ 互为相反数。因此这个 i 的贡献确实为 0 。
求法
单个数
inline int Mu(int n) { int mu = 1; for (int i = 2; i * i <= n; ++i) if (!(n % i)) { if (!(n % (i * i))) return 0; mu *= -1, n /= i; } if (n > 1) mu *= -1; return mu; }
线性筛
inline void sieve(int n) { memset(isp, true, sizeof(isp)); isp[1] = false, mu[1] = 1; for (int i = 2; i <= n; ++i) { if (isp[i]) pri[++pcnt] = i, mu[i] = -1; for (int j = 1; j <= pcnt && i * pri[j] <= n; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) mu[i * pri[j]] = -mu[i]; else { mu[i * pri[j]] = 0; break; } } } }
杜教筛
namespace Mu { map<int, ll> mp; ll f[N], sum[N]; inline void prework() { for (int i = 1; i < N; ++i) sum[i] = sum[i - 1] + f[i]; } ll Sum(ll n) { if (n < N) return sum[n]; if (mp.find(n) != mp.end()) return mp[n]; ll res = 1; for (ll l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res -= 1ll * (r - l + 1) * Sum(n / l); } return mp[n] = res; } } // namespace Mu
莫比乌斯反演
设 f(n),g(n) 为两个数论函数,由 μ∗1=ϵ ,得到:
形式一
设 f(n),g(n) 为两个数论函数,则:
此时 f(n) 称为 g(n) 的莫比乌斯变换,g(n) 称为 f(n) 的莫比乌斯逆变换,即莫比乌斯反演。
形式二
设 f(n),g(n) 为两个数论函数,则:
常见应用
形式一
数论分块即可做到 O(n)−O(√n) 。
形式二
令 dk=T ,则:
数论分块即可做到 O(n)−O(√n) 。
扩展
对于数论函数 f,g 与完全积性函数 t 且满足 t(1)=1 ,则:
证明:
魔力筛
这是一个可以在 O(nloglogn) 的时间复杂度求出任意数论函数与 μ 的狄利克雷卷积的算法。当然,必须保证这个数论函数能被提前计算出来。
设 gi,n=∑d∣nf(d)μ(nd),其中 d 只含前 i 种质因子。则有:
需要滚动数组优化。
解释:第一种情况显然正确。对于第二种,由于每多一个质因子,μ 的取值就会乘以 −1 ,因此上式的意义是强制不选 pi ,然后乘以 −1 累加在答案上。如果含有平方因子,则值为 0 ,不影响答案。
复杂度和埃氏筛一样,为 O(nloglogn) 。
inline void calc(int n) { for (int i = 1; i <= n; ++i) g[i] = f[i]; for (int p : prime) for (int i = n / p; i; --i) g[i * p] = g[i * p] - g[i]; }
应用
P2257 YY的GCD PGCD - Primes in GCD Table
求:
n∑i=1m∑j=1[gcd(i,j)∈prime]n,m≤107
设 T=dk ,则:
n=m 的弱化版是这题:P2568 GCD
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int N = 1e7 + 7; ll f[N], sum[N]; int pri[N], mu[N]; bool isp[N]; int T, n, m, pcnt; inline void sieve() { memset(isp, true, sizeof(isp)); mu[1] = 1, isp[1] = false; for (int i = 2; i < N; ++i) { if (isp[i]) pri[++pcnt] = i, mu[i] = -1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[pri[j] * i] = false; if (i % pri[j]) mu[i * pri[j]] = -mu[i]; else break; } } for (int i = 1; i <= pcnt; ++i) for (int j = 1; pri[i] * j < N; ++j) f[j * pri[i]] += mu[j]; for (int i = 1; i < N; ++i) sum[i] = sum[i - 1] + f[i]; } signed main() { sieve(); scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); if (n > m) swap(n, m); ll ans = 0; for (int l = 1, r = 0; l <= n; l = r + 1) { r = min(n / (n / l), m / (m / l)); ans += (sum[r] - sum[l - 1]) * (n / l) * (m / l); } printf("%lld\n", ans); } return 0; }
设 d(n) 表示 n 的约数个数,求:
n∑i=1m∑j=1d(ij)T,n,m≤5×104
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int N = 5e4 + 7; ll f[N]; int pri[N], mu[N], sum[N]; bool isp[N]; int T, n, m, pcnt; inline void sieve() { memset(isp, true, sizeof(isp)); isp[1] = false, mu[1] = 1; for (int i = 2; i < N; ++i) { if (isp[i]) pri[++pcnt] = i, mu[i] = -1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) mu[i * pri[j]] = -mu[i]; else { mu[i * pri[j]] = 0; break; } } } for (int i = 1; i < N; ++i) sum[i] = sum[i - 1] + mu[i]; for (int i = 1; i < N; ++i) for (int l = 1, r; l <= i; l = r + 1) { r = i / (i / l); f[i] += 1ll * (i / l) * (r - l + 1); } } signed main() { sieve(); scanf("%d", &T); while (T--) { scanf("%d%d", &n, &m); if (n > m) swap(n, m); ll ans = 0; for (int l = 1, r; l <= n; l = r + 1) { r = min(n / (n / l), m / (m / l)); ans += f[n / l] * f[m / l] * (sum[r] - sum[l - 1]); } printf("%lld\n", ans); } return 0; }
求:
n∏i=1n∏j=1lcm(i,j)gcd(i,j)(mod104857601)n≤106
单独考虑下面的部分得到 :
单独考虑指数部分得到:
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int Mod = 104857601; const int N = 1e6 + 7; int pri[N], phi[N], sum[N]; bool isp[N]; int n, pcnt; inline int add(int x, int y) { x += y; if (x >= Mod) x -= Mod; return x; } inline int dec(int x, int y) { x -= y; if (x < 0) x += Mod; return x; } inline int mi(int a, int b) { int res = 1; for (; b; b >>= 1, a = 1ll * a * a % Mod) if (b & 1) res = 1ll * res * a % Mod; return res; } inline void sieve(int n) { memset(isp, true, sizeof(isp)); isp[1] = false, phi[1] = 1; for (int i = 2; i <= n; ++i) { if (isp[i]) pri[++pcnt] = i, phi[i] = i - 1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]]; else { phi[i * pri[j]] = phi[i] * pri[j]; break; } } } for (int i = 1; i <= n; ++i) sum[i] = (sum[i - 1] + phi[i]) % (Mod - 1); } signed main() { scanf("%d", &n); sieve(n); int fac = 1; for (int i = 1; i <= n; ++i) fac = 1ll * fac * i % Mod; int ans = 1ll * mi(fac, n * 2) * fac % Mod * fac % Mod; for (int i = 1; i <= n; ++i) ans = 1ll * ans * mi(mi(i, 4ll * sum[n / i] % (Mod - 1)), Mod - 2) % Mod; printf("%d", ans); return 0; }
求:
n∑i=1n∑j=1⌊nj⌋∑p=1⌊nj⌋∑q=1[gcd(i,j)=1][gcd(p,q)=1](mod998244353)n≤2×109
杜教筛处理 μ 的前缀和即可。
#include <bits/stdc++.h> using namespace std; const int Mod = 998244353; const int N = 1e7 + 7; map<int, int> mp; int pri[N], mu[N], sum[N]; bool isp[N]; int n, pcnt; inline int add(int x, int y) { x += y; if (x >= Mod) x -= Mod; return x; } inline int dec(int x, int y) { x -= y; if (x < 0) x += Mod; return x; } inline void sieve() { memset(isp, true, sizeof(isp)); isp[1] = false, mu[1] = 1; for (int i = 2; i < N; ++i) { if (isp[i]) pri[++pcnt] = i, mu[i] = Mod - 1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) mu[i * pri[j]] = Mod - mu[i]; else { mu[i * pri[j]] = 0; break; } } } for (int i = 1; i < N; ++i) sum[i] = add(sum[i - 1], mu[i]); } int Sum(int n) { if (n < N) return sum[n]; if (mp.find(n) != mp.end()) return mp[n]; int res = 1; for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res = dec(res, 1ll * (r - l + 1) * Sum(n / l) % Mod); } return mp[n] = res; } signed main() { sieve(); scanf("%d", &n); int ans = 0; for (int l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans = add(ans, 1ll * (n / l) * (n / l) % Mod * (n / l) % Mod * dec(Sum(r), Sum(l - 1)) % Mod); } printf("%d", ans); return 0; }
求:
n∑i=1m∑j=1gcd(i,j)k(mod109+7)n,m,k≤5×106
线性筛 g(T)=∑d|Tdkμ(Td) 即可。
#include <bits/stdc++.h> using namespace std; const int Mod = 1e9 + 7; const int N = 5e6 + 7; int pri[N], low[N], g[N], sum[N]; bool isp[N]; int T, n, m, k, pcnt; inline int add(int x, int y) { x += y; if (x >= Mod) x -= Mod; return x; } inline int dec(int x, int y) { x -= y; if (x < 0) x += Mod; return x; } inline int mi(int a, int b) { int res = 1; for (; b; b >>= 1, a = 1ll * a * a % Mod) if (b & 1) res = 1ll * res * a % Mod; return res; } inline void sieve() { memset(isp, true, sizeof(isp)); isp[1] = false, low[1] = 1, g[1] = 1; for (int i = 2; i < N; ++i) { if (isp[i]) { pri[++pcnt] = i, low[i] = i, g[i] = dec(mi(i, k), 1); int x = i; while (1ll * x * i < N) x *= i, low[x] = x, g[x] = dec(mi(x, k), mi(x / i, k)); } for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { int x = i * pri[j]; isp[x] = false; low[x] = i % pri[j] ? pri[j] : low[i] * pri[j]; g[x] = 1ll * g[x / low[x]] * g[low[x]] % Mod; if (!(i % pri[j])) break; } } for (int i = 1; i < N; ++i) sum[i] = add(sum[i - 1], g[i]); } signed main() { scanf("%d%d", &T, &k); sieve(); while (T--) { scanf("%d%d", &n, &m); int ans = 0; if (n > m) swap(n, m); for (int l = 1, r; l <= n; l = r + 1) { r = min(n / (n / l), m / (m / l)); ans = add(ans, 1ll * (n / l) * (m / l) % Mod * dec(sum[r], sum[l - 1]) % Mod); } printf("%d\n", ans); } return 0; }
求:
n∑i=1n∑j=1ijgcd(i,j)(modp)n≤1010
其中 S(n)=n(n+1)2 ,令 T=dk 则:
杜教筛处理 T2φ(T) 的前缀和即可,具体为构造 g(n)=n2 。
#include <bits/stdc++.h> typedef long long ll; using namespace std; const int N = 1e7 + 7; map<ll, int> mp; int pri[N], phi[N], sum[N]; bool isp[N]; ll n; int Mod, pcnt, inv6; inline int add(int x, int y) { x += y; if (x >= Mod) x -= Mod; return x; } inline int dec(int x, int y) { x -= y; if (x < 0) x += Mod; return x; } inline int mi(int a, int b) { int res = 1; for (; b; b >>= 1, a = 1ll * a * a % Mod) if (b & 1) res = 1ll * res * a % Mod; return res; } inline void sieve() { memset(isp, true, sizeof(isp)); isp[1] = false, phi[1] = 1; for (int i = 2; i < N; ++i) { if (isp[i]) pri[++pcnt] = i, phi[i] = i - 1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) phi[i * pri[j]] = phi[i] * phi[pri[j]]; else { phi[i * pri[j]] = phi[i] * pri[j]; break; } } } for (int i = 1; i < N; ++i) sum[i] = add(sum[i - 1], 1ll * i * i % Mod * phi[i] % Mod); } inline int Sum1(ll n) { n %= Mod; return n * (n + 1) / 2 % Mod; } inline int Sum2(ll n) { n %= Mod; return n * (n + 1) % Mod * (n * 2 + 1) % Mod * inv6 % Mod; } int Sum(ll n) { if (n < N) return sum[n]; if (mp.find(n) != mp.end()) return mp[n]; int res = 1ll * Sum1(n) * Sum1(n) % Mod; for (ll l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res = dec(res, 1ll * dec(Sum2(r), Sum2(l - 1)) * Sum(n / l) % Mod); } return mp[n] = res; } signed main() { scanf("%d%lld", &Mod, &n); sieve(); inv6 = mi(6, Mod - 2); int ans = 0; for (ll l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans = add(ans, 1ll * Sum1(n / l) * Sum1(n / l) % Mod * dec(Sum(r), Sum(l - 1)) % Mod); } printf("%d", ans); return 0; }
求:
R∑i1=LR∑i2=L⋯R∑in=L[gcd(i1,i2,⋯,in)=k](mod109+7)n,k≤109 ,L,R≤109 ,R−L≤105
令 l=⌈Lk⌉,r=⌊Rk⌋ ,则:
#include <bits/stdc++.h> using namespace std; const int Mod = 1e9 + 7; const int N = 1e7 + 7; map<int, int> mp; int pri[N], mu[N], sum[N]; bool isp[N]; int n, k, L, R, pcnt; inline int add(int x, int y) { x += y; if (x >= Mod) x -= Mod; return x; } inline int dec(int x, int y) { x -= y; if (x < 0) x += Mod; return x; } inline int mi(int a, int b) { int res = 1; for (; b; b >>= 1, a = 1ll * a * a % Mod) if (b & 1) res = 1ll * res * a % Mod; return res; } inline void sieve() { memset(isp, true, sizeof(isp)); isp[1] = false, mu[1] = 1; for (int i = 2; i < N; ++i) { if (isp[i]) pri[++pcnt] = i, mu[i] = Mod - 1; for (int j = 1; j <= pcnt && i * pri[j] < N; ++j) { isp[i * pri[j]] = false; if (i % pri[j]) mu[i * pri[j]] = Mod - mu[i]; else { mu[i * pri[j]] = 0; break; } } } for (int i = 1; i < N; ++i) sum[i] = add(sum[i - 1], mu[i]); } inline int Sum(int n) { if (n < N) return sum[n]; if (mp.find(n) != mp.end()) return mp[n]; int res = 1; for (int l = 2, r; l <= n; l = r + 1) { r = n / (n / l); res = dec(res, 1ll * (r - l + 1) * Sum(n / l) % Mod); } return mp[n] = res; } signed main() { sieve(); scanf("%d%d%d%d", &n, &k, &L, &R); L = (L - 1) / k, R /= k; int ans = 0; for (int l = 1, r; l <= R; l = r + 1) { r = R / (R / l); if (L / l) r = min(r, L / (L / l)); ans = add(ans, 1ll * mi(R / l - L / l, n) * dec(Sum(r), Sum(l - 1)) % Mod); } printf("%d", ans); return 0; }
本文作者:wshcl
本文链接:https://www.cnblogs.com/wshcl/p/18680385/Mobius
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步