GuGuFishtion (欧拉函数题 gcd=i的对数的处理方法)

原题:hdu 6390

题意:

定义 G ( a , b ) = ϕ ( a b ) ϕ ( a ) ϕ ( b ) ( ϕ ( i ) ) , 求:

a = 1 n ( b = 1 m G ( a , b ) ) ( n , m [ 1 , 1 e 6 ] )

解析:

欧拉函数的公式为:

ϕ ( n ) = n ( 1 1 P 1 ) ( 1 1 P 2 ) . . . ( 1 1 P n ) ( P i n )

那么易得:

G ( a , b ) = ϕ ( a b ) ϕ ( a ) ϕ ( b ) = ( 1 1 Q 1 ) ( 1 1 Q 2 ) . . . ( 1 1 Q n ) ( Q i g c d ( a , b ) )

那么我们要处理的就是 g c d ( a , b ) = i 时的 G ( a , b ) ,以及有多少对a,b的gcd为i

一 : g c d ( a , b ) = i 时的 G ( a , b )

G ( a , b ) = ϕ ( i ) / i , 所以我们可以用预处理欧拉函数差不多的方法预处理出G值

for(D i=2;i<=MAXN;i++){// v为G值
        inv[i]=(mod-mod/i)*inv[mod%i]%mod;//处理逆元
        if(!vis[i]){
            pri[++now]=i;
            v[i]=i*inv[i-1]%mod;//质数的G
        }
        for(D j=1;j<=now&&pri[j]*i<=MAXN;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                v[i*pri[j]]=v[i];// i|pri[j]那么i*pri[j]的质因子==i的质因子
                break;
            }
            v[i*pri[j]]=v[i]*v[pri[j]]%mod;//i没包括pri[j]这个质因子的时候
        }
    }

二 : a [ 1 , n ] , b [ 1 , m ] ( a , b ) g c d i

对于一个数i,在 a [ 1 , n ] , b [ 1 , m ] 的范围内, f [ i ] g c d ( i , 2 i , 3 i . . . )

显然 : f [ i ] = [ n / i ] [ m / i ]

那么我们从大到小维护 f [ i ] ,因为我们要的是 g c d = i 的对数,所以要把 g c d = 2 i 的情况减去


    for(D i=1;i<=MAXN;i++){
        f[i]=(n/i)*(m/i)%mod;
    }
    for(D i=MAXN/2;i>=1;i--){//最高到MAXAN/22i的情况
        for(D j=i+i;j<=MAXN;j+=i){
            f[i]-=f[j];
            if(f[i]<0)f[i]+=mod;
        }
    }


代码:


#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cstring>
#include<algorithm>
#include<set>
#include<map>
#include<list>
#include<vector>
#include<stack>
#include<queue>
#include<ctime>
#include<cstdlib>
#include<sstream>
#include<functional>
using namespace std;
#define D long long
#define F double
#define mmm(a,b) memset(a,b,sizeof(a))
D read(){ D ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}
const int N=1000000;
const F pi=acos(-1);

D n,m,p,mi;
D f[N+9],v[N+9],inv[N+9];
D pri[N+9],now;
bool vis[N+9];
void init(){
    mmm(vis,0);mi=min(m,n);now=0;
    for(D i=1;i<=mi;i++){
        f[i]=(n/i)*(m/i)%p;
    }
    for(D i=mi/2;i>=1;i--){
        for(D j=i+i;j<=mi;j+=i){
            f[i]-=f[j];
            if(f[i]<0)f[i]+=p;
        }
    }
    v[1]=inv[1]=1;
    for(D i=2;i<=mi;i++){
        inv[i]=(p-p/i)*inv[p%i]%p;
        if(!vis[i]){
            pri[++now]=i;
            v[i]=i*inv[i-1]%p;
        }
        for(D j=1;j<=now&&pri[j]*i<=mi;j++){
            vis[i*pri[j]]=1;
            if(i%pri[j]==0){
                v[i*pri[j]]=v[i];
                break;
            }
            v[i*pri[j]]=v[i]*v[pri[j]]%p;
        }
    }
}

int main(){
    int t=read();
    while(t--){
        n=read(),m=read(),p=read();
        init();
        D ans=0;
        for(D i=1;i<=mi;i++)
            ans=(ans+f[i]*v[i])%p;
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/81665804
今日推荐