算法笔记-莫比乌斯反演

莫比乌斯函数 μ ( n ) \mu(n) μ(n)

μ ( n ) = { 1 n = 1 ( − 1 ) k n = p 1 p 2 . . . p k 0 e l s e \mu(n)=\left\{ \begin{array}{cl} 1 && {n = 1}\\ (-1)^k && {n = p_1p_2...p_k}\\ 0 && {else}\\ \end{array} \right. μ(n)= 1(1)k0n=1n=p1p2...pkelse
n n n有平方因子时, μ ( n ) = 0 \mu(n) = 0 μ(n)=0.
n n n没有平方因子时, μ ( n ) \mu(n) μ(n)取决于分解的素数个数

性质
  • 对任意正整数n, ∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n} \mu(d) = [n = 1] dnμ(d)=[n=1]
  • 对任意正整数n, ∑ d ∣ n μ ( d ) d = ϕ ( n ) n \sum_{d|n} \frac{\mu(d)}{d} = \frac{\phi(n)}{n} dndμ(d)=nϕ(n)

莫比乌斯函数是积性函数,可以利用线性筛求出莫比乌斯函数

void get_mu(int n){
	mu[1] = 1;
	for(int i = 2; i <= n; i++){
		if(!vis[i]){
			prime[++cnt] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= cnt&&i*prime[j] <= n; j++){
			vis[i*prime[j]] = 1;
			if(i%prime[j] == 0){
				mu[i*prime[j]] = 0; //也可以直接break 
				break;
			}
			else
				mu[i*prime[j]] = -mu[i];
		}
	}
}


莫比乌斯反演

F(n)与f(n)定义在非负整数集上,且满足: F ( n ) = ∑ d ∣ n f ( d ) F(n) = \sum\limits_{d|n}f(d) F(n)=dnf(d)则: f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) f(n) = \sum\limits_{d|n}\mu(d)F(\frac{n}{d}) f(n)=dnμ(d)F(dn)
F(n)与f(n)定义在非负整数集上,且满足: F ( n ) = ∑ n ∣ d f ( d ) F(n) = \sum\limits_{n|d}f(d) F(n)=ndf(d)则: f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n) = \sum\limits_{n|d}\mu(\frac{d}{n})F(d) f(n)=ndμ(nd)F(d)

YY的GCD
题意:

∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = p r i m e ] \sum\limits_{i=1}\limits^{N}\sum\limits_{j=1}\limits^{M}[gcd(i,j) = prime] i=1Nj=1M[gcd(i,j)=prime]

数据组数 T = 1 0 4 N , M ≤ 1 0 7 T = 10^4\quad N, M \le 10^7 T=104N,M107

解析:

f ( d ) f(d) f(d) g c d ( i , j ) = d gcd(i,j) = d gcd(i,j)=d的个数,设 F ( n ) F(n) F(n) g c d ( i , j ) = k n ( k ≥ 1 ) gcd(i,j) = kn (k \ge 1) gcd(i,j)=kn(k1) 的个数 f ( d ) = ∑ i = 1 N ∑ j = 1 M [ g c d ( i , j ) = d ] f(d) = \sum\limits_{i=1}\limits^{N}\sum\limits_{j=1}\limits^{M}[gcd(i,j) = d] f(d)=i=1Nj=1M[gcd(i,j)=d] F ( n ) = ∑ n ∣ d f ( d ) F(n) = \sum\limits_{n|d}f(d) F(n)=ndf(d) F ( n ) F(n) F(n)定义可知, F ( n ) = ⌊ N n ⌋ ⌊ M n ⌋ F(n) = \lfloor \frac{N}{n}\rfloor \lfloor \frac{M}{n} \rfloor F(n)=nNnM

答案为: ∑ p ∈ p r i m e s f ( p ) \sum\limits_{p \in primes } f(p) pprimesf(p)莫比乌斯反演:
∑ p ∈ p r i m e s ∑ p ∣ d μ ( d p ) F ( d ) \sum\limits_{p \in primes}\sum\limits_{p|d} \mu(\frac{d}{p})F(d) pprimespdμ(pd)F(d) d 1 = d p d_1 = \frac{d}{p} d1=pd ∑ p ∈ p r i m e s ∑ d 1 = 1 m i n ( ⌊ N p ⌋ , ⌊ M p ⌋ ) μ ( d 1 ) F ( d 1 p ) \sum\limits_{p \in primes}\sum\limits_{d_1 = 1} \limits^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)}\mu(d_1)F(d_1p) pprimesd1=1min(⌊pN,pM⌋)μ(d1)F(d1p)代入 F ( d 1 p ) F(d_1p) F(d1p) ∑ p ∈ p r i m e s ∑ d 1 = 1 m i n ( ⌊ N p ⌋ , ⌊ M p ⌋ ) μ ( d 1 ) ⌊ N d 1 p ⌋ ⌊ M d 1 p ⌋ \sum\limits_{p \in primes}\sum\limits_{d_1 = 1} \limits^{min(\lfloor \frac{N}{p}\rfloor,\lfloor \frac{M}{p}\rfloor)}\mu(d_1)\lfloor \frac{N}{d_1p}\rfloor\lfloor \frac{M}{d_1p}\rfloor pprimesd1=1min(⌊pN,pM⌋)μ(d1)d1pNd1pM T = d 1 p T = d_1p T=d1p ∑ T = 1 m i n ( N , M ) ∑ t ∣ T , t ∈ p r i m e s μ ( ⌊ T t ⌋ ) ⌊ N T ⌋ ⌊ M T ⌋ \sum\limits_{T=1}\limits^{min(N,M)}\sum\limits_{t|T,t\in primes}\mu(\lfloor \frac{T}{t} \rfloor)\lfloor \frac{N}{T}\rfloor\lfloor \frac{M}{T}\rfloor T=1min(N,M)tT,tprimesμ(⌊tT⌋)TNTM ∑ T = 1 m i n ( N , M ) ⌊ N T ⌋ ⌊ M T ⌋ ∑ t ∣ T , t ∈ p r i m e s μ ( ⌊ T t ⌋ ) \sum\limits_{T=1}\limits^{min(N,M)} \lfloor \frac{N}{T}\rfloor\lfloor \frac{M}{T}\rfloor\sum\limits_{t|T,t\in primes}\mu(\lfloor \frac{T}{t} \rfloor) T=1min(N,M)TNTMtT,tprimesμ(⌊tT⌋)
前边可以整除分块,后边可以预处理前缀和

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e7+10;
int mu[maxn], prime[maxn], vis[maxn];
int tot;
ll sum[maxn], f[maxn];
inline ll read(){//读入优化 
	char ch;
	while((ch=getchar())<'0'||ch>'9');
	ll res = ch-48;
	while((ch=getchar())>='0'&&ch<='9')
		res = res*10+ch-48;
	return res;
}
void get_mu(int n){
	mu[1] = 1;
	for(int i = 2; i <= n; i++){
		if(!vis[i]){
			prime[++tot] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= tot && i*prime[j] <= n; j++){
			vis[i*prime[j]] = 1;
			if(i % prime[j] == 0){
				mu[i*prime[j]] = 0;
				break;
			}
			else
				mu[i*prime[j]] = -mu[i];
		}
	}
	for(int j = 1; j <= tot; j++){
		for(int i = 1; i*prime[j] <= n; i++){
			f[i*prime[j]] += mu[i];
		}
	}
	for(int i = 1; i <= n; i++)
		sum[i] = sum[i-1]+f[i];
}
int N, M;
void solve(){
	ll res = 0;
	//scanf("%lld %lld", &N, &M);
	//cin >> N >> M;
	N = read(), M = read();
	if(N > M)
		swap(N, M);
	int r;
	for(int l = 1; l <= N; l = r+1){
		r = min(N/(N/l), M/(M/l));
		res += 1ll*(N/l)*(M/l)*(sum[r]-sum[l-1]);
	}
	printf("%lld\n", res);
	//cout << res << endl;
}
signed main(){
	int T;
	cin >> T;
	get_mu(10000000);
	while(T--)
		solve();
	return 0;
}


ZAP-Queries
题意:

∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = k ] \sum\limits_{i=1}\limits^{a}\sum\limits_{j=1}\limits^{b}[gcd(i,j) = k] i=1aj=1b[gcd(i,j)=k]

解析:

∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = k ] \sum\limits_{i=1}\limits^{a}\sum\limits_{j=1}\limits^{b}[gcd(i,j) = k] i=1aj=1b[gcd(i,j)=k] ∑ i = 1 ⌊ a k ⌋ ∑ j = 1 ⌊ b k ⌋ [ g c d ( i , j ) = 1 ] \sum\limits_{i=1}\limits^{\lfloor\frac{a}{k}\rfloor}\sum\limits_{j=1}\limits^{\lfloor\frac{b}{k}\rfloor}[gcd(i,j) = 1] i=1kaj=1kb[gcd(i,j)=1] ∑ i = 1 ⌊ a k ⌋ ∑ j = 1 ⌊ b k ⌋ ∑ d ∣ g c d ( i , j ) μ ( d ) \sum\limits_{i=1}\limits^{\lfloor\frac{a}{k}\rfloor}\sum\limits_{j=1}\limits^{\lfloor\frac{b}{k}\rfloor}\sum\limits_{d|gcd(i,j)}\mu(d) i=1kaj=1kbdgcd(i,j)μ(d) ∑ i = 1 ⌊ a k ⌋ ∑ j = 1 ⌊ b k ⌋ ∑ d = 1 ⌊ a k ⌋ μ ( d ) [ d ∣ g c d ( i , j ) ] \sum\limits_{i=1}\limits^{\lfloor\frac{a}{k}\rfloor}\sum\limits_{j=1}\limits^{\lfloor\frac{b}{k}\rfloor}\sum\limits_{d=1}\limits^{\lfloor\frac{a}{k}\rfloor}\mu(d)[d|gcd(i,j)] i=1kaj=1kbd=1kaμ(d)[dgcd(i,j)] μ ( d ) 提前: \mu(d)提前: μ(d)提前: ∑ d = 1 ⌊ a k ⌋ μ ( d ) ∑ i = 1 ⌊ a k ⌋ ∑ j = 1 ⌊ b k ⌋ [ d ∣ g c d ( i , j ) ] \sum\limits_{d=1}\limits^{\lfloor\frac{a}{k}\rfloor}\mu(d)\sum\limits_{i=1}\limits^{\lfloor\frac{a}{k}\rfloor}\sum\limits_{j=1}\limits^{\lfloor\frac{b}{k}\rfloor}[d|gcd(i,j)] d=1kaμ(d)i=1kaj=1kb[dgcd(i,j)] ∑ d = 1 ⌊ a k ⌋ μ ( d ) ⌊ a k d ⌋ ⌊ b k d ⌋ \sum\limits_{d=1}\limits^{\lfloor\frac{a}{k}\rfloor}\mu(d)\lfloor\frac{a}{kd}\rfloor\lfloor\frac{b}{kd}\rfloor d=1kaμ(d)kdakdb
同上,后面部分可以整除分块,前面部分可以预处理前缀和

#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 5e4+10;
int vis[maxn], prime[maxn], tot;
int mu[maxn], sum[maxn];
void get_mu(int n){
	mu[1] = 1;
	for(int i = 2; i <= n; i++){
		if(!vis[i]){
			prime[++tot] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= tot && i*prime[j] <= n; j++){
			vis[i*prime[j]] = 1;
			if(i%prime[j] == 0){
				mu[i*prime[j]] = 0;
				break;
			} 
			else
				mu[i*prime[j]] = -mu[i];
		}
	}
	for(int i = 1; i <= n; i++)
		sum[i] = sum[i-1]+mu[i];
}
int a, b, d;
void solve(){
	cin >> a >> b >> d;
	if(a > b)
		swap(a, b);
	a = a/d, b = b/d;
	ll res = 0;
	int r = 0;
	for(int l = 1; l <= a; l = r+1){
		r = min(a/(a/l), b/(b/l));
		res += 1ll*(a/l)*(b/l)*(sum[r]-sum[l-1]);
	}
	printf("%lld\n", res);
	return ;
}
int main(){
	get_mu(50000);
	int T;
	cin >> T;
	while(T--)
		solve();
	return 0;
}


Problem b
题意:

∑ i = a b ∑ j = c d [ g c d ( i , j ) = k ] \sum\limits_{i=a}\limits^{b}\sum\limits_{j=c}\limits^{d}[gcd(i,j) = k] i=abj=cd[gcd(i,j)=k]

解析:

同上题,先求出 ∑ i = 1 a ∑ j = 1 b [ g c d ( i , j ) = k ] \sum\limits_{i=1}\limits^{a}\sum\limits_{j=1}\limits^{b}[gcd(i,j) = k] i=1aj=1b[gcd(i,j)=k] 的答案,然后容斥一下

代码:
#include<iostream>
using namespace std;
typedef long long ll;
const int maxn = 5e4+10;
int vis[maxn], prime[maxn], tot;
int mu[maxn], sum[maxn];
void get_mu(int n){
	mu[1] = 1;
	for(int i = 2; i <= n; i++){
		if(!vis[i]){
			prime[++tot] = i;
			mu[i] = -1;
		}
		for(int j = 1; j <= tot && i*prime[j] <= n; j++){
			vis[i*prime[j]] = 1;
			if(i%prime[j] == 0){
				mu[i*prime[j]] = 0;
				break;
			} 
			else
				mu[i*prime[j]] = -mu[i];
		}
	}
	for(int i = 1; i <= n; i++)
		sum[i] = sum[i-1]+mu[i];
}
int a, b, c, d, k;
ll ans;
ll solve(int a, int b, int k){
	//cin >> a >> b >> d;
	if(a > b)
		swap(a, b);
	a = a/k, b = b/k;
	ll res = 0;
	int r = 0;
	for(int l = 1; l <= a; l = r+1){
		r = min(a/(a/l), b/(b/l));
		res += 1ll*(a/l)*(b/l)*(sum[r]-sum[l-1]);
	}
	//printf("%lld\n", res);
	return res;
}
int main(){
	get_mu(50000);
	int T;
	cin >> T;
	while(T--){
		cin >> a >> b >> c >> d >> k;
		ans = solve(b, d, k)-solve(a-1, d, k)-solve(b, c-1, k)+solve(a-1, c-1, k);
		printf("%lld\n", ans);
	}
	return 0;
}

https://www.cnblogs.com/peng-ym/p/8652288.html
https://oi-wiki.org/math/number-theory/mobius/

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值