1. 程式人生 > >GuGuFishtion(hdu 6390 尤拉函式+莫比烏斯函式)

GuGuFishtion(hdu 6390 尤拉函式+莫比烏斯函式)

題目:

題意:

Gu(a,b)=\frac{\phi (a,b)}{\phi (a)*\phi (b)} ,已知m,n,p,求 (\sum_{a=1}^{m}\sum_{b=1}^{n}Gu(a,b)) (mod p)  。

思路:

尤拉函式性質:\phi (p^{k})=(p-1)*p^{k-1} (p為質數)。

一個數肯定能表示成若干個質數的乘積,因此,設gcd(a,b)=p1^{k1}*p2^{k2}*p3^{k3}*...*pn^{kn}

Gu(a,b)=\frac{\phi (a,b)}{\phi (a)*\phi (b)}

 =\frac{\phi (p1^{2k1}*p2^{2k2}*p3^{2k3}*...*pn^{2kn})}{\phi (p1^{k1}*p2^{k2}*p3^{k3}*...*pn^{kn})^{2}} (其餘的項上下展開後都可以約掉,因為它們互質)

=\frac{(p1-1)*(p2-1)*(p3-1)*...*(pn-1)*p1^{2k1-1}*p2^{2k2-1}*p3^{2k3-1}*...*pn^{2kn-1}}{(p1-1)^{2}*(p2-1)^{2}*(p3-1)^{2}*...*(pn-1)^{2}*p1^{2k1-2}*p2^{2k2-2}*p3^{2k3-2}*...*pn^{2kn-2}}

=\frac{p1*p2*p3*..*pn}{(p1-1)*(p2-1)*(p3-1)*...*(pn-1)}

=\frac{p1*p2*p3*...*pn*p1^{k1-1}*p2^{k2-1}*p3^{k3-1}*...*pn^{kn-1}}{(p1-1)*(p2-1)*(p3-1)*...*(pn-1)*p1^{k1-1}*p2^{k2-1}*p3^{k3-1}*...*pn^{kn-1}}

=\frac{p1^{k1}*p2^{k2}*p3^{k3}*...*pn^{kn}}{\phi (p1^{k1}*p2^{k2}*p3^{k3}*...*pn^{kn})}=\frac{gcd(a,b)}{\phi (gcd(a,b))}

a[i]=\frac{i}{\phi (i)}

f(m,n)=\sum_{a=1}^{m}\sum_{b=1}^{n}Gu(a,b)=\sum_{a=1}^{m}\sum_{b=1}^{n}a[gcd(a,b)]

=\sum_{d=1}^{min(m,n)}\sum_{a=1}^{m}\sum_{b=1}^{n}a[d]*[gcd(a,b)==d]

=\sum_{d=1}^{min(m,n)}\sum_{a=1}^{m/d}\sum_{b=1}^{n/d}a[d]*[gcd(a,b)==1]

g(m,n)=\sum_{a=1}^{m}\sum_{b=1}^{n}[gcd(a,b)==1]

=\sum_{a=1}^{m}\sum_{b=1}^{n}\sum_{d|gcd(a,b)}^{ }\mu(d)=\sum_{d=1}^{min(m,n)}\mu (d)*\frac{m}{d}*\frac{n}{d}

\mu (d)為莫比烏斯函式,有如下性質:

\sum_{d|n}^{ }\mu (d)=1(當n=1時)

\sum_{d|n}^{ }\mu (d)=0(當n>1時)

當gcd(a,b)==1時,\sum_{d|gcd(a,b)}^{ }\mu(d)=1,當gcd(a,b)!=1時,\sum_{d|gcd(a,b)}^{ }\mu(d)=0,等價於[gcd(a,b)==1]

最後一步的轉化中,\frac{m}{d}表示在a\in [1,m]中能被d整除的數的個數,\frac{n}{d}表示在b\in [1,n]中能被d整除的數的個數,因此,兩者的乘積就表示為在\sum_{a=1}^{m}\sum_{b=1}^{n}累加的過程中滿足 d|gcd(a,b) 的情況的個數,因此,最後兩個式子等價。

\therefore f(m,n)=\sum_{d=1}^{min(m,n)}a[d]*\left ( \sum_{a=1}^{m/d}\sum_{b=1}^{n/d}[gcd(a,b)==1] \right )

=\sum_{d=1}^{min(m,n)}a[d]*g(\frac{m}{d},\frac{n}{d})

時間複雜度計算:

a[i]陣列,尤拉函式,莫比烏斯函式均能線性預處理。

計算\sum_{d=1}^{min(m,n)}的時間複雜度為O(n);

計算g(\frac{m}{d},\frac{n}{d})的總時間為:

\frac{n}{1}+\frac{n}{2}+\frac{n}{3}+...+\frac{n}{n}=n(1+\frac{1}{2}+\frac{1}{3}+...+\frac{1}{n})=nln(n)+C (C為尤拉常數)

因為有n項,所以每項的平均時間為ln(n)

因此,總時間複雜度為O(nln(n))

程式碼:

因為\phi (i)的值總是小於 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;
}