Description
Given a prime P, 2 <= P < 231, an integer B, 2 <= B < P, and an integer N, 2 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such that
BL == N (mod P)
Input
Read several lines of input, each containing P,B,N separated by a space,
Output
for each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print “no solution”.
The solution to this problem requires a well known result in number theory that is probably expected of you for Putnam but not ACM competitions. It is Fermat’s theorem that states
B(P-1) == 1 (mod P)
for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat’s theorem is that for any m
B(-m) == B(P-1-m) (mod P) .
Sample Input
5 2 1
5 2 2
5 2 3
5 2 4
5 3 1
5 3 2
5 3 3
5 3 4
5 4 1
5 4 2
5 4 3
5 4 4
12345701 2 1111111
1111111121 65537 1111111111
Sample Output
0
1
3
2
0
3
1
2
0
no solution
no solution
1
9584351
462803587
分析:显然是一道BSGS模版题。
代码:
/**************************************************************
Problem: 3239
User: beginend
Language: C++
Result: Accepted
Time:172 ms
Memory:118488 kb
****************************************************************/
#include <iostream>
#include <cstdio>
#include <cmath>
const int maxn=5000001;
using namespace std;
long long b,a,p,block,i,t,power;
long long g[maxn],cnt;
struct node
{
long long x,pow;
}hash[maxn];//一个hash表
long long f(long long x)//hash函数
{
return x%maxn;
}
void updata(long long x,long long c)//插入
{
long long id=f(x);
while (hash[id].x!=0) id=(id+1)%maxn;
hash[id].x=x;
hash[id].pow=c;
g[++cnt]=id;
}
long long find(long long x)//查询
{
long long id=f(x);
while (hash[id].x!=0)
{
if (hash[id].x==x) return hash[id].pow;
id=(id+1)%maxn;
}
return -1;
}
int main()
{
while (scanf("%lld%lld%lld",&p,&a,&b)!=EOF)
{
if (b==1) //特判一下1
{
printf("0\n");
continue;
}
block=trunc(sqrt(p))+1;//分块,先处理a^0到a^(block-1)
a%=p; b%=p; cnt=0;
power=1;
for (i=0;i<block;i++)
{
updata((power*b)%p,i);//把a^0到a^(block-1)压人hash表
power=(power*a)%p;
}
t=1;
for (i=1;i<=block;i++)
{
t=(t*power)%p;//一个(a^block)^i,
long long j=find(t);//寻找是否有解
if (j!=-1)
{
printf("%lld\n",i*block-j);//当前幂次为i*block-j
break;
}
}
if (i>block) printf("no solution\n");
for (i=1;i<=cnt;i++) hash[g[i]].x=0;//清空hash表
}
return 0;
}