【洛谷】P2257 YY的GCD(莫比乌斯反演)

原题链接

题意

T 组询问,每次询问求:

i=1ni=1m[gcd(i,j)prime]

T=104,n,m107

思路

不难想到枚举质数,将原式化简为:

pprimei=1ni=1m[gcd(i,j)=p]

按照套路,提出后面的 p,得到:

pprimei=1npi=1mp[gcd(i,j)=1]

套用莫比乌斯函数,得到:

pprimei=1npi=1mpd|gcd(i,j)μ(d)

将莫比乌斯函数提到最前面去,得到:

d=1μ(d)pprimei=1npi=1mp[d|i][d|j]

后面的 d|i 其实就是在枚举 1npd 的倍数有多少个,那么其实就是 npd,带入原式,得到:

d=1μ(d)pprimenpdmpd

到目前为止,利用数论分块,单次询问的复杂度为 O(×n)。考虑进一步优化,设 k=pd,带入原式:

pprimed=1μ(d)nkmk

枚举一下 k,提到式子的前方,得到:

k=1nkmkp|k,pprimeμ(kp)

发现后面那个式子可以预处理掉,于是复杂度就为 O(Tn)

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e7+10;
#define LL long long
int f[N],mu[N],n,prime[N],tot;bool vis[N];LL sum[N];
void init()
{
	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&&prime[j]*i<N;j++)
		{
			vis[prime[j]*i]=true;
			if(i%prime[j]==0) {mu[prime[j]*i]=0;break;}
			mu[prime[j]*i]=-mu[i];
		} 
	}
	for(int i=1;i<=tot;i++) for(int j=prime[i];j<N;j+=prime[i]) sum[j]+=mu[j/prime[i]];
	for(int i=2;i<N;i++) sum[i]+=sum[i-1];
}
LL solve(int n,int m)
{
	LL res=0;
	for(int l=1,r=0;l<=min(n,m);l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		res+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
	}
	return res;
}
int main()
{
	init();int n,m,T;scanf("%d",&T);while(T--) scanf("%d%d",&n,&m),printf("%lld\n",solve(n,m));
	return 0;
}
posted @   曙诚  阅读(19)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示