题干:
给定一个素数P, 2<=P<
,两个正整数B , 2 <=B<P; N , 1<=N<P;
求一个正整数L,使得
思路:
本体是一个BSGS模板题。
先来看下需要了解的定理。
因为给定的P为素数,根据费马小定理:
≡ 1 (mod P)
根据逆元的定义:
a*b ≡ 1 (mod P),则b就是a在模除P的情况下的逆元。
B的逆元可以由费马小定理推出:
* B ≡ 1 (mod P)
BSGS的思路是:设m=ceil(sqrt(P ))
令L=i*m+j, 即
变形为
= >
因为模运算不能有除法,所以这里用
在模P的逆元 即
然后将从0到m的所有
存进map中,再遍历从0到m的所有
,
如果
==
,则 L=i*m+j;如果找不到则无解。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <map>
using namespace std;
typedef long long ll;
ll qc(ll a,ll b,ll c)
{
ll ans=1;
while(b)
{
if(b&1)
ans=(ans*a)%c;
a=(a*a)%c;
b>>=1;
}
return ans%c;
}
ll bsgs(ll a,ll b,ll c)
{
ll m=ceil(sqrt(c*1.0));
ll t=qc(a,c-m-1,c),y=1; //求逆元
//printf("%lld\n",m);
map<ll,ll>x;
x[1]=m;
for(int i=1;i<m;i++){
y=(y*a)%c;
if(!x[y])
x[y]=i;
}
for(int i=0;i<m;i++){
if(x[b]) //查找map表
{
int pos=x[b];
x.clear();
return m*i+(pos==m?0:pos);
}
b=(b%c*t%c)%c;
}
return -1;
}
int main()
{
ll a,b,c;
while(scanf("%lld%lld%lld",&c,&a,&b)!=EOF)
{
//printf("%lld %lld %lld\n",a,b,c);
ll ans=bsgs(a,b,c);
if(ans==-1)
printf("no solution\n");
else
printf("%lld\n",ans);
}
return 0;
}