Codeforces 1027G X-mouse in the Campus

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Myriad_Dreamin/article/details/82503489

(Codeforces 1027G) 考虑两个整数 1 m , n 10 14 , ( m , n ) = 1 , 问若定义等价类 x ¯ = { a | a m k = x , a Z n } ,这样的等价类有多少个?
M = m , n ,由欧拉定理 m φ ( n ) 1 ( m , n ) = 1 , 这是一个 φ ( n ) 阶循环群.
那么 x ¯ = x M ,容易由此知道 φ ( n ) = c i | x ¯ i | ,所有不同的 x ¯ 就是答案。
但是直接计算等价类的复杂度是 O ( n ) ,那就 TLE 了.
于是考虑一个加速:对于任意 a Z n , ( a m k , n ) = ( a , n ) ,所以记 φ ( n / d ) = k = 1 n [ ( k , n ) = d ] ,答案就是 d | n φ ( n / d ) | d ¯ | .
现在问题来了. | d ¯ | 如何计算?
min k : d x k d ( mod n ) , d d = n d x k d + d d ( mod n ) x k 1 ( mod n d )
注意到 k | φ ( d ) | φ ( n ) ,于是求 φ ( n ) 的素因子然后枚举即可…

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
inline long long mul(long long a,long long b,long long c){
    long long res=(a*b-(long long)((double)a*b/c+0.1)*c)%c;
    return res<0?res+c:res;
}
inline long long qp(long long a,long long b,long long mod){
    a%=mod;long long tmp=a,res=1;
    while(b){
        if(b&1)res=mul(res,tmp,mod);
        tmp=mul(tmp,tmp,mod); b>>=1;
    }
    return res;
}
long long m,sqrtm,x,factor[200],fact[100000],f[100000],prim[100000];
int n=0,ptop=0,tol=0;
inline void calfact(long long m){
    for(long long i=1,mi;i<=sqrtm;i++){
        mi=m/i;
        if(i*mi==m){
            if(i!=mi)fact[++n]=mi;
            fact[++n]=i;
        }
    }
    sort(fact+1,fact+1+n);
}
inline void calprim(long long m,long long *prim,int &ptop){
    for(long long i=2;i<=sqrtm;i++){
        if(m%i==0){
            prim[++ptop]=i;
            while(m%i==0)m/=i;
        }
    }
    if(m>1)prim[++ptop]=m;
    return ;
}
inline long long Euler(long long n){
    long long phi=n;
    for(int i=1;i<=ptop;i++){
        if(phi%prim[i]==0)phi-=phi/prim[i];
    }
    return phi;
}
inline long long cal(long long m){
    long long res=0,tmpres,trueres,Eulerm=Euler(m);
    if(Eulerm>1)calprim(Eulerm,factor,tol);else factor[++tol]=1;
    for(int i=1;i<=n;i++){
        tmpres=trueres=Euler(fact[i]);
        if(tmpres>1){
            for(int j=1;j<=tol;j++){
                while(tmpres%factor[j]==0&&
                    qp(x,tmpres/factor[j],fact[i])==1)tmpres/=factor[j];
            }
        }
        res+=trueres/tmpres;
    }
    return res;
}
int main(){
    scanf("%I64d%I64d",&m,&x);
    sqrtm=sqrt(m+1);
    calfact(m);
    calprim(m,prim,ptop);
    printf("%I64d\n",cal(m));
}

猜你喜欢

转载自blog.csdn.net/Myriad_Dreamin/article/details/82503489
今日推荐