GuGuFishtion(hdu 6390 尤拉函式+莫比烏斯函式)
阿新 • • 發佈:2019-01-04
題目:
題意:
設 ,已知m,n,p,求
。
思路:
尤拉函式性質: (p為質數)。
一個數肯定能表示成若干個質數的乘積,因此,設。
(其餘的項上下展開後都可以約掉,因為它們互質)
設 。
設
設
為莫比烏斯函式,有如下性質:
(當n=1時)
(當n>1時)
當gcd(a,b)==1時,,當gcd(a,b)!=1時,
,等價於
。
最後一步的轉化中,表示在
中能被d整除的數的個數,
表示在
中能被d整除的數的個數,因此,兩者的乘積就表示為在
累加的過程中滿足
的情況的個數,因此,最後兩個式子等價。
時間複雜度計算:
a[i]陣列,尤拉函式,莫比烏斯函式均能線性預處理。
計算的時間複雜度為O(n);
計算的總時間為:
(C為尤拉常數)
因為有n項,所以每項的平均時間為 。
因此,總時間複雜度為 。
程式碼:
因為的值總是小於 i ,所以預處理 max(m,n) 個逆元已經足夠了。
#include <iostream> #include <string> #include <cstdio> #include <cstring> #include <cmath> #include <set> #include <vector> #include <cstdlib> #include <algorithm> using namespace std; typedef long long ll; const int MAX = 1e6+10; ll m,n,mod; ll prime[MAX],phi[MAX]; int cnt=0; bool flag[MAX]; int mu[MAX]; ll a[MAX]; ll inv[MAX]; int len; //預處理尤拉函式phi[ ]和莫比烏斯函式mu[ ] void init() { memset(flag,false,sizeof(flag)); phi[1]=1; mu[1]=1; for(int i=2;i<MAX;i++){ if(!flag[i]){ prime[cnt++]=i; phi[i]=i-1; mu[i] = -1; } for(int j=0;j<cnt&&i*prime[j]<MAX;j++){ flag[i*prime[j]]=true; if(i%prime[j]==0){ phi[i*prime[j]]=phi[i]*prime[j]; mu[i * prime[j]] = 0; break; } else phi[i*prime[j]]=phi[i]*(prime[j]-1); mu[i * prime[j]] = -mu[i]; } } } void gao() { //預處理逆元 inv[1]=1; for(int i=2;i<=len;i++) inv[i] = 1LL * inv[mod%i]*(mod-mod/i)%mod; //預處理a[ ]陣列 ( a[i]=i/phi[i] ) for(int i=1;i<=len;i++){ a[i]=1ll*i*inv[phi[i]]%mod; } } int main() { int T; scanf("%d",&T); init(); while(T--) { scanf("%lld%lld%lld",&m,&n,&mod); len=min(m,n); gao(); ll ans=0; for(int i=1;i<=len;i++){ int tmp1=m/i,tmp2=n/i; int v=min(tmp1,tmp2); //計算g(m/d,n/d) ll g=0; for(int j=1;j<=v;j++) g=(g+1ll*mu[j]*(tmp1/j)*(tmp2/j)+mod)%mod; ans=(ans+a[i]*g)%mod; } printf("%lld\n",ans); } return 0; }