求最小正整数x,A^x=1(mod M)求阶模板

整数的阶:设a和n是互素的正整数,使得a^x=1(mod n)成立的最小的正整数x称为a模n的阶

//求阶模板:A^x=1(mod M),调用GetJie(A,M)
//输入:10^10>A,M>1
//输出:无解返回-1,有解返回最小正整数x
//复杂度:O(M^(0.5))
long long gcd(long long a,long long b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

//欧拉函数:复杂度O(n^(0.5)),返回[1,n-1]中所有和n互素的数的个数和
long long phi(long long x)
{
    long long sum=x;
    for(long long i=2;i*i<=x;i++)
    {
        if(x%i==0)
        {
            sum=sum-sum/i;
            while(x%i==0) x/=i;
        }
    }
    if(x!=1) sum=sum-sum/x;
    return sum;
}

long long Mod_Mul(long long a,long long b,long long mod)
{
    long long sum=0;
    while(b)
    {
        if(b&1) sum=(sum+a)%mod;
        b>>=1;
        a = (a+a)%mod;
    }
    return sum;
}


//a^b%mod 快速幂
long long Quk_Mul(long long a,long long b,long long mod)
{
    long long qsum=1;
    while(b)
    {
        if(b&1) qsum=Mod_Mul(qsum,a,mod);
        b>>=1;
        a=Mod_Mul(a, a, mod);
    }
    return qsum;
}

long long GetJie(long long A,long long M)
{
    long long d = gcd(A,M);
    if(d != 1) return -1;
    long long m=phi(M);
    //然后对m进行拆分
    long long prm[40],prmcnt[40];
    int pcnt=0;
    memset(prmcnt,0,sizeof(prmcnt));
    long long tm = m;
    for(long long i=2;i*i<=tm;i++)
    {
        if(tm%i==0)
        {
            prm[pcnt]=i;
            while(tm%i==0)
            {
                prmcnt[pcnt]++;
                tm/=i;
            }
            pcnt++;
        }
    }
    if(tm!=1)
    {
        prm[pcnt]=tm;
        prmcnt[pcnt]=1;
        pcnt++;
    }
    for(int i=0;i<pcnt;i++)
    {
        for(int j=0;j<prmcnt[i];j++)
        {
            if( Quk_Mul(A, m/prm[i], M)==1 )
            {
                m/=prm[i];
            }
        }
    }
    return m;
}

//再加一个打素数表的。理论上会快10倍。

//求阶模板:A^x=1(mod M),调用GetJie(A,M)
//输入:10^10>A,M>1
//输出:无解返回-1,有解返回最小正整数x
//复杂度:M^(0.5)

long long PRIME[100100];


long long gcd(long long a,long long b)
{
    if(b==0) return a;
    return gcd(b,a%b);
}

//欧拉函数:复杂度O(n^(0.5)),返回[1,n-1]中所有和n互素的数的个数和
long long phi(long long x)
{
    long long sum=x;
    long long p = PRIME[0];
    for(int i=0;p*p<=x;i++)
    {
        if(0 == x%p)
        {
            sum=sum-sum/p;
            while(x%p==0) x/=p;
        }
        p=PRIME[i+1];
    }
    if(x!=1) sum=sum-sum/x;
    return sum;
}

long long Mod_Mul(long long a,long long b,long long mod)
{
    long long sum=0;
    while(b)
    {
        if(b&1) sum=(sum+a)%mod;
        b>>=1;
        a = (a+a)%mod;
    }
    return sum;
}


//a^b%mod 快速幂
long long Quk_Mul(long long a,long long b,long long mod)
{
    long long qsum=1;
    while(b)
    {
        if(b&1) qsum=Mod_Mul(qsum,a,mod);//mod不是很大的时候这一步可以去掉
        b>>=1;
        a=Mod_Mul(a, a, mod);//
    }
    return qsum;
}

long long GetJie(long long A,long long M)
{
    long long d = gcd(A,M);
    if(d != 1) return -1;
    long long m=phi(M);
    //然后对m进行拆分
    long long prm[40],prmcnt[40];
    int pcnt=0;
    memset(prmcnt,0,sizeof(prmcnt));
    long long tm = m;
    long long p=PRIME[0];
    for(long long i=0;p*p<=tm;i++)
    {
        if(tm%p==0)
        {
            prm[pcnt]=p;
            while(tm%p==0)
            {
                prmcnt[pcnt]++;
                tm/=p;
            }
            pcnt++;
        }
        p=PRIME[i+1];
    }
    if(tm!=1)
    {
        prm[pcnt]=tm;
        prmcnt[pcnt]=1;
        pcnt++;
    }
    for(int i=0;i<pcnt;i++)
    {
        for(int j=0;j<prmcnt[i];j++)
        {
            if( Quk_Mul(A, m/prm[i], M)==1 )
            {
                m/=prm[i];
            }
        }
    }
    return m;
}

void getprime(long long up)
{
    bool pmark[200100];
    memset(pmark,0,sizeof(pmark));
    int pcnt=0;
    PRIME[pcnt++]=2;
    for(int i=2;i<=up;i+=2) pmark[i]=1;
    for(int i=3;i<=up;i+=2)
    {
        if(pmark[i]==0)
        {
            PRIME[ pcnt++ ] = i;
            for(int j=i+i;j<=up;j+=i)
            {
                pmark[j]=1;
            }
        }
    }
}
原文地址:https://www.cnblogs.com/chenhuan001/p/5029375.html