P2257 YY的GCD

洛谷题目链接

第一道自己认真做的数论

有两种方法,默认((N<M))

方法一:

我们需要求:$$sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=prime]$$

我们会想到枚举其中的素数:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=p]$$

再一步变形:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(frac{i}{p},frac{j}{p})=1]$$

[sumlimits_{p epsilon prime} sumlimits_{i=1}^{leftlfloor frac{N}{p} ight floor} sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} [gcd(i,j)=1] ]

是不是看到中括号里面的东西想到了什么?莫比乌斯函数~~

因为莫比乌斯函数的性质:$$sumlimits_{d|n} mu (d)=[n=1]$$

所以原式可化为:$$sumlimits_{p epsilon prime} sumlimits_{i=1}^{leftlfloorfrac{N}{p} ight floor} sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} sumlimits_{d|gcd(i,j)} mu (d)$$

我们按照套路把(d)提前,其中(d|gcd(i,j))这个条件可以转化成(d|i,d|j),我们就枚举(d):$$sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloorfrac{N}{p} ight floor} mu (d) sumlimits_{i=1}^{leftlfloorfrac{N}{p} ight floor} [d|i] sumlimits_{j=1}^{leftlfloorfrac{M}{p} ight floor} [d|j]$$

根据整出分块,没学过的可以看看我的其他博客,我们就可以把最后两个(sum)消去了:$$sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloorfrac{N}{p} ight floor} mu (d) leftlfloor frac{N}{d imes p} ight floor leftlfloor frac{M}{d imes p} ight floor$$

这里我们再用一个小技巧,我们用(T)代替(d imes p)

[sumlimits_{p epsilon prime} sumlimits_{T=1}^N mu (frac{T}{p}) leftlfloor frac{N}{T} ight floor leftlfloor frac{M}{T} ight floor ]

稍微变一下:$$sumlimits_{T=1}^N sumlimits_{p epsilon prime} mu (frac{T}{p}) leftlfloor frac{N}{T} ight floor leftlfloor frac{M}{T} ight floor$$

这样的话,我们就先线性筛出(mu)函数,然后把(sumlimits_{p epsilon prime} mu (frac{T}{p}))处理出来,做一下前缀和,就可以用整除分块来(O(sqrt n))回答每个询问了

接下来是美滋滋的代码时间~~~

#include<iostream>
#include<cstdio>
#define N 10000007
#define int long long
using namespace std;
int T,n,m,ans,cnt;
int mu[N],prime[N>>2],num[N];
bool isp[N];
void Get_mu()
{
	mu[1]=1;
	for(int i=2;i<=N-7;++i)
	{
		if(!isp[i])
		{
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=cnt&&(prime[j]*i)<=N-7;++j)
		{
			isp[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
			else
				mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=cnt;++i)
	{
		int res=1;
		for(int j=prime[i];j<=N-7;j+=prime[i],++res)
			num[j]+=mu[res];
	}
	for(int i=2;i<=N-7;++i)
		num[i]+=num[i-1];
}
signed main()
{
	Get_mu();
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld%lld",&n,&m);
		if(n>m)
			swap(n,m);
		ans=0;
		for(int l=1,r;l<=n;l=r+1)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=(num[r]-num[l-1])*(n/l)*(m/l);
		}
		printf("%lld
",ans);
	}
	return 0;
}

方法二:

我们要求:$$sumlimits_{i=1}^N sumlimits_{j=1}^M [gcd(i,j)=prime]$$

我们设(F(d))表示(d|gcd(i,j))(1<=i<=N,1<=j<=M)((i,j))对数

很明显:$$F(d)=sumlimits_{i=1}^N sumlimits_{j=1}^M [d|gcd(i,j)]$$

(d|gcd(i,j))可以化为(d|i,d|j):$$F(d)=sumlimits_{i=1}^N [d|i] sumlimits_{j=1}^M [d|j]$$

[=leftlfloor frac{N}{d} ight floor leftlfloor frac{M}{d} ight floor ]

我们再设(f(d))表示(gcd(i,j)=d)(1<=i<=N,1<=j<=M)((i,j))对数

可得$$F(d)=sumlimits_{d|n}^N f(n)$$

莫比乌斯反演得:$$f(d)=sumlimits_{d|n}^N mu (frac{n}{d}) F(n)$$

而我们题目中就是要求:$$Ans=sumlimits_{p epsilon prime} f(p)$$

(f(p))带入:$$Ans=sumlimits_{p epsilon prime} sumlimits_{p|d} mu (frac{d}{p}) leftlfloor frac{N}{d} ight floor leftlfloor frac{M}{d} ight floor$$

我们改为枚举(frac{d}{p}):$$Ans=sumlimits_{p epsilon prime} sumlimits_{d=1}^{leftlfloor frac{N}{p} ight floor} mu (d) leftlfloor frac{N}{d imes p} ight floor leftlfloor frac{M}{d imes p} ight floor$$

那么再像上面那个方法一样用(T)代替(d imes p)即可

代码也是一样的~~~

原文地址:https://www.cnblogs.com/yexinqwq/p/11104889.html