HDU 6390 GuGuFishtion(尤拉函式+莫比烏斯反演)
阿新 • • 發佈:2018-12-19
#include<bits/stdc++.h> using namespace std; #define debug puts("YES"); #define rep(x,y,z) for(int (x)=(y);(x)<(z);(x)++) #define ll long long #define lrt int l,int r,int rt #define lson l,mid,rt<<1 #define rson mid+1,r,rt<<1|1 #define root l,r,rt #define mst(a,b) memset((a),(b),sizeof(a)) const int maxn =1e6+5; const int ub=1e6; /* 題目大意:求式子。 無語到最後我把式子化簡到最後卻T了。 只要看出來euler(a)*euler(b)/euler(a*b), 最後通過一個技巧可以變成gcd(a,b)/euler(gcd(a,b)), 莫比烏斯反演看到gcd啥的就瞬間思路很簡單了, 到最後是要處理個二維字首互質二元組個數, 總體複雜度是O(nlogn)。 */ ll n,m,mod; ll ans,maxv; ///篩法篩莫比烏斯函式和尤拉函式 int prim[maxn/10],tot=0; int vis[maxn],euler[maxn],miu[maxn]; ll G[maxn],g[maxn],inv[maxn]; void get_inv() { inv[1]=1; for(int i=2;i<maxv ;i++) inv[i]=1LL*(mod-mod/i)*inv[mod%i]%mod; } void sieve() { miu[1]=euler[1]=1; for(int i=2;i<maxn;i++) { if(vis[i]==0) prim[tot++]=i,miu[i]=-1,euler[i]=i-1; for(int j=0;j<tot;j++) { if(1LL*i*prim[j]>=maxn) break; int k=i*prim[j];vis[k]=1; if(i%prim[j]) { miu[k]=-miu[i]; euler[k]=euler[i]*(prim[j]-1); } else { euler[k]=euler[i]*prim[j]; break; } } } for(int i=1;i<maxn;i++) miu[i]+=miu[i-1]; } ll cal(ll l,ll r) { ll minv=min(l,r),ret=0; for(int i=1,j;i<=minv;i=j+1) { j=min(l/(l/i),r/(r/i)); ret+=(miu[j]-miu[i-1]+mod)*(l/i)%mod*(r/i)%mod; ret%=mod; } return ret; } int main() { int t;scanf("%d",&t); sieve(); while(t--) { scanf("%lld%lld%lld",&n,&m,&mod); if(n>m) swap(n,m); ans=0,maxv=n+1; get_inv(); for(int i=1,j;i<maxv;i++) { ans+=i*inv[euler[i]]%mod*cal(n/i,m/i)%mod; ans%=mod; } printf("%lld\n",ans); } return 0; }