poj 2417 Discrete Logging 求解模方程a^x=b(mod n),n为素数+模板题(baby_step giant_step)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <map>
#include <iostream>
#include <algorithm>
using namespace std;
#define LL long long
//快速幂求a^b
LL pow_mod(LL a,LL b,LL n)
{
    LL s=1;
    while(b)
    {
        if(b&1)
            s=(s*a)%n;
        a=(a*a)%n;
        b=b>>1;
    }
    return s;
}
//求解模方程a^x=b(mod n)。n为素数,无解返回-1
//费马小定理a^(n-1)=1(mod n),n为素数。a^0=1,所以循环节小于等于n,即如果存在解,则最小解x<=n
LL log_mod (LL a,LL b,LL n)
{
    LL m,v,e=1,i;
    m=ceil(sqrt(n+0.5));     //x=i*m+j
    //v=inv(pow_mod(a,m,n),n);  //a^m*v=1(mod n)
    v=pow_mod(a,n-m-1,n);
    map<LL,LL>x;
    x[1]=m;
    for(i=1;i<m;i++)  //建哈希表,保存x^0,x^1,...,x^m-1
    {
        e=(e*a)%n;
        if(!x[e])x[e]=i;
    }
    for(i=0;i<m;i++)//每次增加m次方,遍历所有1<=x<=n
    {
        if(x[b])
        {
            LL num=x[b];
            x.clear();//需要清空,不然会爆内存
            return i*m+(num==m?0:num);
        }
        b=(b*v)%n;   //b=b/(a^m)
    }

    return -1;
}
int main()
{
    LL a,b,n;
    while(scanf("%I64d%I64d%I64d",&n,&a,&b)!=EOF)
    {
        LL ans=log_mod(a,b,n);
        if(ans==-1)printf("no solution\n");
        else printf("%I64d\n",ans);
    }
    return 0;
}
/*
    求解模方程a^x=b(mod n),n为素数。
    模板题。
    时间复杂度O(sqrt(n)*logn)
*/

你可能感兴趣的:(模方程,baby_step,giant_step)