Discrete Logging
Description
Given a prime
P
,
That is , find an integer
Input
Read several lines of input, each containing
P
,
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”.
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
Hint
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
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
Source
Waterloo Local 2002.01.26
Solution
Baby Step Giant Step 算法的模板题。
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#define LL long long
#define HASH_MOD 786433
using namespace std;
LL p,b,n,ans;
LL fx,fy;
struct map{
LL h[800000],v[800000],nxt[800000],ne[800000];
void clear(){
memset(nxt,-1,sizeof nxt);
memset(h,-1,sizeof h);
ne[786433]=0;
for(LL i=0;i<786433;i++)ne[i]=i;
}
LL fi(LL x){
LL tmp=x,pre;
while(tmp!=ne[tmp])tmp=ne[tmp];
while(x!=tmp){pre=ne[x];ne[x]=tmp;x=pre;}
return tmp;
}
void insert(LL x,LL y){
LL mx=x%HASH_MOD;
while(nxt[mx]!=-1)
mx=nxt[mx];
nxt[mx]=fi(0);
ne[nxt[mx]]=ne[nxt[mx]]+1;
h[nxt[mx]]=x;
v[nxt[mx]]=y;
}
LL find(LL x){
LL mx=x%HASH_MOD;
while(x!=h[mx]&&nxt[mx]!=-1)mx=nxt[mx];
if(x!=h[mx])return -1;
return v[mx];
}
};
map hash;
LL power(LL x,LL y,LL Mod){
x%=Mod;
LL ans=1;
while(y){
if(y&1)ans=ans*x%Mod;
x=x*x%Mod;
y>>=1;
}
return ans;
}
LL ex_gcd(LL x,LL y,LL &a,LL &b){
if(y==0){a=1;b=0;return x;}
LL fa,fb;
LL c=ex_gcd(y,x%y,fa,fb);
a=fb;
b=fa-fb*(x/y);
return c;
}
int main(){
while(scanf("%lld%lld%lld",&p,&b,&n)!=EOF){
b%=p;n%=p;
hash.clear();
LL MAXN=ceil(sqrt((double)p));
bool flag=false;
for(LL i=0;i<MAXN;i++){
LL tmp=power(b,i,p);
if(tmp==n){printf("%lld\n",i);flag=true;break;}
hash.insert(tmp,i);
}
if(flag)continue;
LL QMM=power(b,MAXN,p);
if(QMM==n){printf("%lld\n",MAXN);goto nxt;}
ex_gcd(QMM,p,fx,fy);
fx=(fx*n%p+p)%p;
if((ans=hash.find(fx))!=-1){printf("%lld\n",ans+MAXN);goto nxt;}
for(LL i=2;i<=MAXN;i++){
LL tmp=power(QMM,i,p);
ex_gcd(tmp,p,fx,fy);
fx=(fx*n%p+p)%p;
if((ans=hash.find(fx))!=-1){printf("%lld\n",ans+MAXN*i);goto nxt;}
}
printf("no solution\n");
nxt:;
}
return 0;
}