[题解]YY的GCD【Luogu P2257】

YY的GCD

一.提要

​ 这片题解是一个大的学习笔记中的附属品,其中没有什么变换讲解,如果看不懂请先一步到这篇文章

二.解题

[sumlimits_{pin P} sumlimits_{x=1}^{n} sumlimits_{y=1}^m[gcd(x,y)=p] ]

[=sumlimits_{pin P} sumlimits_{x=1}^{lfloorfrac{n}{p} floor} sumlimits_{y=1}^{lfloorfrac{m}{p} floor} sumlimits_{d|gcd(x,y)}mu(d)\ ]

[=sumlimits_{pin P} sumlimits_{d=1}^{lfloorfrac{min(n,m)}{p} floor} mu(d)lfloorfrac{n}{pd} floor lfloorfrac{m}{pd} floor\ ]

[=sumlimits_{t=1}^{min(n,m)} lfloorfrac{n}{t} floor lfloorfrac{m}{t} floor sumlimits_{pin P,p|t}mu(frac{t}{p}) ]

第二步运用了(mu*1=epsilon)

第三步运用了一个……没有名字的定理来划掉了两个求和(在程序实现的时候需要数论分块解决(lfloorfrac{n}{pd} floor lfloorfrac{m}{pd} floor)的不同取值)

第四步换元,调换顺序

三.CODE

#define ll long long
#define m_for(i,a,b) for(int i=a;i<=b;++i)
inline int read() {
	int s=0,w=1;
	char ch=getchar();
	while(ch<'0'||ch>'9') {
		if(ch=='-')w=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
	return s*w;
}
const int MAXN=10000005;
int prime[MAXN],tot,mu[MAXN];
bool vis[MAXN];
void m_p(int x){
	mu[1]=1;
	m_for(i,2,x){
		if(!vis[i])prime[++tot]=i,mu[i]=-1;
		for(int j=1;i*prime[j]<=x&&j<=tot;++j){
			vis[i*prime[j]]=1;
			if(i%prime[j]==0)break;
			mu[i*prime[j]]=-mu[i];
		}
	}
}
int g[MAXN];
ll sum[MAXN];
void m_mu(int x){
	m_for(i,1,tot){
		for(int j=1;j*prime[i]<=x;++j){
			g[j*prime[i]]+=mu[j];
		}
	}
	m_for(i,1,x)sum[i]=sum[i-1]+1LL*g[i];
}
int t,n,m;
ll ans;
int main(){
	m_p(MAXN);
	m_mu(MAXN);
	t=read();
	while(t--){
		n=read();m=read();
		if(n>m)swap(n,m);
		ans=0;
		for(int l=1,r;l<=n;l=r+1){
			r=min(n/(n/l),min(m/(m/l),n));
			ans+=1LL*(n/l)*(m/l)*(sum[r]-sum[l-1]);
			//cout<<ans<<endl;
		}
		cout<<ans<<endl;
	}
}
原文地址:https://www.cnblogs.com/clockwhite/p/12251034.html