[莫比乌斯反演]YY的GCD[证明已补]

BZOJ2820
莫比乌斯反演模板

证明:
莫比乌斯反演的两种形式:
1. F ( n ) = ∑ d ∣ n f ( d ) ⇒ f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}{f(d)}\Rightarrow f(n) = \sum_{d|n}{\mu(d) F(\frac{n}{d}) } F(n)=dnf(d)f(n)=dnμ(d)F(dn)
2. F ( n ) = ∑ n ∣ d f ( d ) ⇒ f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) F(n)=\sum_{n|d}{f(d)}\Rightarrow f(n) = \sum_{n|d}{\mu(\frac{d}{n}) F(d) } F(n)=ndf(d)f(n)=ndμ(nd)F(d)

在本题中,我们设 f ( n ) f(n) f(n) 为满足 g c d ( a , b ) = d gcd(a,b)=d gcd(a,b)=d ( a , b ) (a,b) (a,b)的对数
F ( d ) F(d) F(d)为满足 d ∣ g c d ( a , b ) d|gcd(a,b) dgcd(a,b) ( x , y ) (x,y) (x,y)的对数
那么得到 F ( x ) = n d ∗ m x F(x)=\frac{n}{d}*\frac{m}{x} F(x)=dnxm
反演上式得: f ( x ) = ∑ x ∣ d μ ( d x ) F ( d ) = ∑ x ∣ d μ ( d x ) n d ∗ m x f(x)=\sum_{x|d}{\mu(\frac{d}{x})F(d)}=\sum_{x|d}{\mu(\frac{d}{x})}\frac{n}{d}*\frac{m}{x} f(x)=xdμ(xd)F(d)=xdμ(xd)dnxm

d是质数,所以
a n s = ∑ p m i n ( n , m ) ( ∑ d m i n ( n , m ) μ ( d ) n p d ∗ m p d ) ans=\sum_{p}^{min(n,m)}(\sum_{d}^{min(n,m)}{\mu(d)\frac{n}{pd}*\frac{m}{pd}}) ans=pmin(n,m)(dmin(n,m)μ(d)pdnpdm)

明显会T,继续优化:
T = p d T=pd T=pd a n s = ∑ p m i n ( n , m ) n T ∗ m T ( ∑ p ∣ T μ ( T p ) ) ans=\sum_{p}^{min(n,m)}\frac{n}{T}*\frac{m}{T}(\sum_{p|T}{\mu(\frac{T}{p})}) ans=pmin(n,m)TnTm(pTμ(pT))

所以预处理 T T T ∑ p ∣ T μ ( T p ) \sum_{p|T}{\mu(\frac{T}{p})} pTμ(pT),就做完了

Code:

#include
#define int long long
using namespace std;
inline int read(){
	int res=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-') f=-f;ch=getchar();}
	while(isdigit(ch)) {res=(res<<1)+(res<<3)+(ch^48);ch=getchar();}
	return res*f;
}
const int N=10001000;
int cnt=0,u[N],pt[N],g[N],pri[N],sum[N];
inline void init(){
	memset(pt,0,sizeof(pt));
	u[1]=1;
	for(int i=2;i<=N;i++){
		if(!pt[i]){
			pri[++cnt]=i;
			u[i]=-1;
			g[i]=1;
		}
		for(int j=1;j<=cnt && i*pri[j]<N;j++){
			pt[i*pri[j]]=1;
			if(i%pri[j]){
				u[i*pri[j]]=-u[i];
				g[i*pri[j]]=u[i]-g[i];
			}
			else{
				u[i*pri[j]]=0;
				g[i*pri[j]]=u[i];
				break;	
			}
		}
	}
	sum[0]=0;
	for(int i=1;i<N;i++) sum[i]=sum[i-1]+g[i];
}
signed main(){
	init();
	int t=read();
	while(t--){
		int n=read(),m=read();
		if(n>m) swap(n,m);
		int ans=0;
		for(int i=1,last;i<=n;i=last+1){
			last=min(n/(n/i),m/(m/i));
			ans+=(n/i)*(m/i)*(sum[last]-sum[i-1]);
		}
		cout<<ans<<'\n';
	}
	return 0;
}

你可能感兴趣的:(莫比乌斯反演,莫比乌斯反演)