http://www.lydsy.com/JudgeOnline/problem.php?id=2820
首先按照套路
ans
=ΣprimeΣ(i=1,n)Σ(j=1,m)[gcd(i,j)=prime]
=ΣprimeΣ(i=1,[n/prime])Σ(j=1,[m/prime])[gcd(i,j)=1]
=ΣprimeΣ(i=1,min(n,m)/prime)μ(i)*[n/i]*[m/i]
这样做枚举n以内的质数,其个数为n/ln(n),复杂度是O(T√n*n/ln(n)).
好像会TLE
那么进一步优化式子
ans
=ΣprimeΣ(i=1,min(n,m)/prime)μ(i)*[n/i]*[m/i]
=Σ(T=1,min(n,m))[n/T]*[m/T]*Σ(prime,prime|T)μ(T/prime)
这里更改了枚举顺序枚举T=i*prime
设f(T)=Σ(prime,prime|T)μ(T/prime)
ans
=Σ(T=1,min(n,m))[n/T]*[m/T]*f[T]
f[T]可以线性地按照定义预处理出来
因为质数个数为n/ln(n),每个质数做筛法期望复杂度为log(n)
总复杂度为O(n*log(n)/ln(n))≈O(n)
所以,按照套路做,复杂度为O(T√n)
#include<cstdio> typedef long long ll; ll ans; const int N=1e7+11; const int maxn=1e7; int T; int pr[N],miu[N],f[N],sum[N]; bool ip[N]; inline void shai_fa(){ miu[1]=1; for(register int i=2;i<=maxn;++i){ if(!ip[i]) miu[pr[++pr[0]]=i]=-1; for(register int j=1;pr[j]*i<=maxn&&j<=pr[0];++j){ ip[i*pr[j]]=1; if(i%pr[j]==0) break; miu[i*pr[j]]=-miu[i]; } } for(register int i=1;i<=pr[0];++i) for(register int k=1,j=pr[i];j<=maxn;j+=pr[i],++k) f[j]+=miu[k]; for(register int i=1;i<=maxn;++i) sum[i]=sum[i-1]+f[i]; } int n,m,pos,a; inline int min(int a,int b){return a<b?a:b;} int main(){ shai_fa(); scanf("%d",&T); while(T--){ scanf("%d%d",&n,&m); a=min(n,m); ans=0; for(register int i=1;i<=a;i=pos+1){ pos=min(n/(n/i),m/(m/i)); ans+=1ll*(sum[pos]-sum[i-1])*(n/i)*(m/i); } printf("%lld ",ans); } return 0; }