【数论】HDU6390 GuGuFishtion

分析:

//详情参见problem B
很明显,如果 ( x , y ) = 1 (“()”表示最大公因数)
那么 φ ( x y ) = φ ( x ) φ ( y )

那么如果 ( x , y ) > 1
x y 唯一分解:
x = p x 1 k x 1 × p x 2 k x 2 × × p x m k x m
y = p y 1 k y 1 × p y 2 k y 2 × × p y n k y n

然后发现,若x存在某个质因子 p a ,且y存在同样的一个质因子 p b ,那么它们的乘积中就有 p a + b 这个质因子。
根据 φ 函数的定义: φ ( n ) = ( p 1 k 1 p 1 k 1 1 ) ( p 2 k 2 p 2 k 2 1 ) ( p 3 k 3 p 3 k 3 1 )
那么对于 φ ( x ) , p 的贡献为 p a p a 1
对于 φ ( y ) , p 的贡献为 p b p b 1
对于 φ ( x y ) , p 的贡献为 p a + b p a + b 1
发现: ( p a p a 1 ) × ( p b p b 1 ) = p a + b 2 × p a + b 1 + p a + b 2 = ( p a + b p a + b 1 ) × p 1 p

所以,定义 g = ( x , y )
g = p g 1 k g 1 × p g 2 k g 2 × × p g s k g s
那么 φ ( x y ) φ ( x ) φ ( y ) = p g 1 p g 1 1 × p g 2 p g 2 1 × p g 3 p g 3 1

所以只需要枚举一下gcd=g,然后求所有gcd为g的方案数即可。莫比乌斯反演一下就出来了。。(其实用不着反演,直接用莫比乌斯函数的性质上去容斥就可以了)

#include<cstdio>
#include<cstring>
#include<algorithm>
#define SF scanf
#define PF printf
#define MAXN 1000000
using namespace std;
typedef long long ll;
int tot;
int primes[MAXN+10],isprime[MAXN+10],minp[MAXN+10],mu[MAXN+10];
ll fspx[MAXN+10];
ll p,n,m;
ll fsp(ll x,int y){
    ll res=1;
    while(y){
        if(y&1)
            res=res*x%p;
        x=x*x%p;
        y>>=1;    
    }
    return res;
}
void prepare(){
    mu[1]=1;
    for(int i=2;i<=MAXN;i++){
        if(isprime[i]==0){
            primes[++tot]=i;
            minp[i]=i;
            mu[i]=-1;
        }
        for(int j=1;primes[j]*i<=MAXN;j++){
            isprime[i*primes[j]]=1;
            if(i%primes[j]==0){
                minp[i*primes[j]]=primes[j];
                mu[i*primes[j]]=0;
                break;
            }
            minp[i*primes[j]]=primes[j];
            mu[i*primes[j]]=-mu[i];
        }
    }
    for(int i=1;i<=MAXN;i++)
        mu[i]=mu[i-1]+mu[i];
}
int t;
ll ans;
ll work(ll x,ll y){
    if(x>y)
        swap(x,y);
    ll last=0,res=0;
    for(ll i=1;i<=x;i=last+1){
        last=min(x/(x/i),y/(y/i));
        res+=1ll*(x/i)*(y/i)%p*(mu[last]-mu[i-1])%p;
        res%=p;
    }
    return (res+p)%p;
}
ll solve(ll x){
    ll x1=x;
    ll s=1;
    ll s1=1;
    while(x!=1ll){
        if(s1%minp[x]!=0){
            (s*=1ll*minp[x]*fspx[minp[x]]%p)%=p;
            s1*=minp[x];
        }
        x/=minp[x];
    }
    ll sumx=work(n/x1,m/x1);
    ll res=sumx*s%p;
    return res;
}
int main(){
    prepare();
    SF("%d",&t);
    while(t--){
        ans=0;
        SF("%I64d%I64d%I64d",&n,&m,&p);
        for(int i=1;i<=tot&&primes[i]<=min(n,m);i++){
            fspx[primes[i]]=fsp(primes[i]-1,p-2);
        }
        for(int i=2;i<=min(n,m);i++){
            //PF("{%d %lld}\n",i,solve(i));
            (ans+=solve(i))%=p;
        }
        (ans+=work(n,m))%=p;
        ans=(ans+p)%p;
        PF("%I64d\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/81662577