#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)
*/
poj 2417 Discrete Logging 求解模方程a^x=b(mod n),n为素数+模板题(baby_step giant_step)
最新推荐文章于 2019-03-21 14:18:52 发布