【数论】HDU6390 GuGuFishtion

分析:

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

那么如果 (x,y)>1 ( x , y ) > 1
xy x 、 y 唯一分解:
x=pkx1x1×pkx2x2××pkxmxm x = p x 1 k x 1 × p x 2 k x 2 × … … × p x m k x m
y=pky1y1×pky2y2××pkynyn y = p y 1 k y 1 × p y 2 k y 2 × … … × p y n k y n

然后发现,若x存在某个质因子 pa p a ,且y存在同样的一个质因子 pb p b ,那么它们的乘积中就有 pa+b p a + b 这个质因子。
根据 φ φ 函数的定义: φ(n)=(pk11pk111)(pk22pk212)(pk33pk313) φ ( 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 φ ( x ) , p 的贡献为 papa1 p a − p a − 1
对于 φ(y),p φ ( y ) , p 的贡献为 pbpb1 p b − p b − 1
对于 φ(xy),p φ ( x ∗ y ) , p 的贡献为 pa+bpa+b1 p a + b − p a + b − 1
发现: (papa1)×(pbpb1)=pa+b2×pa+b1+pa+b2=(pa+bpa+b1)×p1p ( 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 = ( x , y )
g=pkg1g1×pkg2g2××pkgsgs g = p g 1 k g 1 × p g 2 k g 2 × … … × p g s k g s
那么 φ(xy)φ(x)φ(y)=pg1pg11×pg2pg21×pg3pg31 φ ( 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);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值