hdu 多校数论 GuGuFishtion
容斥+gcd+欧拉函数
求出1-n 和 1-m所有gcd(i,j)==x对数
x的范围1-min(n,m)
分解x的质因子 (1-1/p)...
q[x]=(1-1/p1)*(1-1/p2)/...
p是x的质因子
ans=sigma(q[x]*gcd(i,j)==x的对数) 1<=x<=min(n,m)
#include<stdio.h> #include<string.h> #include<math.h> #include<vector> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e6+5; int phi[maxn],vis[maxn],pre[maxn],top; ll num[maxn],q[maxn]; ll f[maxn],g[maxn]; ll qpow(ll a,ll b,ll c) { ll ans=1; while(b) { if(b&1) ans=ans*a%c; a=a*a%c; b>>=1; } return ans; } void init() { int i,j; for(i=1; i<maxn; i++) phi[i]=i; for(i=2; i<maxn; i+=2) phi[i]/=2; for(i=3; i<maxn; i+=2) if(phi[i]==i) { for(j=i; j<maxn; j+=i) phi[j]=phi[j]/i*(i-1); } top=0; memset(vis,0,sizeof(vis)); for(i=2; i<maxn; i++) { if(!vis[i]) { pre[top++]=i; } for(j=0; pre[j]*i<maxn; j++) { vis[pre[j]*i]=1; if(i%pre[j]==0) break; } } } void init1(ll p) { int i,j,k; for(i=0; i<top; i++) { k=pre[i]; q[k]=qpow(pre[i]-1,p-2,p); q[k]=1ll*q[k]*(pre[i])%p; } for(i=1; i<maxn; i++) num[i]=1; for(i=0;i<top;i++) { for(j=pre[i];j<maxn;j+=pre[i]) num[j]=1ll*num[j]*q[pre[i]]%p; } } int main() { int i,j,k,t,n,m,z; ll ans,p; scanf("%d",&t); init(); while(t--) { scanf("%d%d%I64d",&m,&n,&p); init1(p); memset(f,0,sizeof(f)); memset(g,0,sizeof(g)); z=min(n,m); for(i=1; i<=z; i++) f[i]=1ll*(n/i)*(m/i)%p; ll sum; for(i=z; i>=1; i--) { sum=0; for(j=i+i; j<=z; j+=i) { sum+=g[j]; sum=sum%p; } g[i]=(f[i]-sum+p)%p; } ans=0; for(i=1; i<=z; i++) { ans+=1ll*g[i]*num[i]%p; ans=ans%p; } printf("%I64d\n",ans%p); } return 0; }