Discrete Logging(poj 2417)

高次同余方程。   BL == N (mod P)求解最小的L。

/*
    A^x=B(mod C)
    设x=i*m-j(其中m=ceil(sqrt C))
    并且i∈[1,m],j∈[0,m],以保证x能取到所有的0~C-1之间的数。
    为什么只取到0~C-1就行了呢?
    根据费马小定理 a^(p-1)=1(mod p)(p是素数),我们可以得到
        a^(k mod p-1)=a^k(mod p)
    即当k>p-1时,会出现类似于循环节的东西。
    那么我们可以得到变形之后的式子
        A^(i*m-j)=B(mod C)
    化简之后为
        A^(i*m)=B*A^j(mod C) 
    现在只需要枚举所有的j,然后把它们放到hash里,再枚举i,得到的第一个即为答案。 
*/
#include<cstdio>
#include<iostream>
#include<cmath>
#include<map>
#define lon long long
using namespace std;
lon A,B,C;
map<lon,int> hash;
lon poww(lon a,lon b){
    lon base=a,r=1;
    while(b){
        if(b&1) r*=base;r%=C;
        base*=base;base%=C;
        b>>=1;
    }
    return r;
}
int main(){
    while(scanf("%lld%lld%lld",&C,&A,&B)!=EOF){
        if(A%C==0){
            printf("no solution
");
            continue;
        }
        hash.clear();
        lon m=ceil(sqrt(C));
        lon ans;
        for(int i=0;i<=m;i++){
            if(!i){
                ans=B%C;hash[ans]=i;
                continue;
            }
            ans=(ans*A)%C;hash[ans]=i;
        }
        ans=1;lon t=poww(A,m);bool fl=false;
        for(int i=1;i<=m;i++){
            ans=(ans*t)%C;
            if(hash[ans]){
                ans=i*m-hash[ans];
                ans=(ans%C+C)%C;
                printf("%lld",ans);printf("
");
                fl=true;
                break;
            }
        }
        if(!fl) printf("no solution
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/harden/p/6512350.html