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

来源:互联网 发布:刷信誉源码平台 编辑:程序博客网 时间:2024/04/27 13:31
#include <cstdio>#include <cstring>#include <cmath>#include <map>#include <iostream>#include <algorithm>using namespace std;#define LL long long//快速幂求a^bLL 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<=nLL 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)*/