离散对数

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
//返回a*b%n,要求0<=a,b<n 
ll mul_mod(ll a,ll b,ll n){
    return a*b%n; 
}
//返回a^p%n,要求0<=a<n 
ll pow_mod(ll a,ll p,ll n)
{   
    ll ans=1;  
    while(p>0){  
        if(p&1) ans=(ans*a)%n;  
        a=(a*a)%n;  
        p>>=1;  
    }  
    return ans;
}
//扩展欧几里得算法 
void gcd(ll a,ll b,ll &d,ll &x,ll &y)
{
    if(!b){
        d=a;
        x=1,y=0;
    }
    else{
        gcd(b,a%b,d,y,x);
        y-=(a/b)*x;
    }
} 
//计算模n下a的逆,如果不存在逆,返回-1 
ll inv(ll a,ll n)
{
    ll d,x,y;
    gcd(a,n,d,x,y);
    return d==1?(x+n)%n:-1;
}
//求解模方程a^x=b(mod n)n为素数。无解返回-1 
ll log_mod(ll a,ll b,ll n)
{
    ll e=1;
    ll m=(ll)sqrt(n+0.5);
    ll v=inv(pow_mod(a,m,n),n);
    map<ll,ll> x;
    x[1]=0;
    for(ll i=1;i<m;i++){
        e=mul_mod(e,a,n);
        if(!x.count(e)) x[e]=i;
    }
    for(ll i=0;i<m;i++){
        if(x.count(b)) return i*m+x[b];
        b=mul_mod(b,v,n);
    }
    return -1;
} 
int main()
{
    ll a,b,n;
    scanf("%lld%lld%lld",&a,&b,&n);
    printf("%lld",log_mod(a,b,n));
}

 

posted @ 2017-02-16 15:41  despair_ghost  阅读(181)  评论(0编辑  收藏  举报