Discrete Logging
Time Limit: 5000MS | Memory Limit: 65536K | |
Total Submissions: 6683 | Accepted: 2963 |
Description
Given a prime P, 2 <= P < 2
31, an integer B, 2 <= B < P, and an integer N, 1 <= 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".
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
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) .
Source
bsgs算法:全称baby-step-giant-step,用于求解形如A^x=B (mod p)的方程的最小整数解(x>=0)。
当p为素数时,可以用bsgs算法求解。
求解方法:
若A与p不互质,则无解。
求出m=ceil(sqrt(p)),令x=i*m-j.化简,得
(A^m)^i=A^j*B (mod p)
枚举 j = 0..m, 将A^j*B存入哈希表。
枚举 i = 1..m, 当取到最小的 i 使得上面的等式成立时,则X min = i*m-j.
当p不是素数时,可以使用扩展bsgs算法。
#include <cstdio>
#include <iostream>
#include <string.h>
#include <string>
#include <map>
#include <queue>
#include <deque>
#include <vector>
#include <set>
#include <algorithm>
#include <math.h>
#include <cmath>
#include <stack>
#include <iomanip>
#define mem0(a) memset(a,0,sizeof(a))
#define meminf(a) memset(a,0x3f,sizeof(a))
using namespace std;
typedef long long ll;
typedef long double ld;
typedef double db;
const int inf=0x3f3f3f3f;
const ll llinf=0x3f3f3f3f3f3f3f3f;
const ld pi=acos(-1.0L);
map<ll,int> mp;
ll fastpower(ll base,ll index,ll mod) {
ll ans,now;
if (index<0) return 1;
ans=1;
now=base;
ll k=index;
while (k) {
if (k%2) ans=ans*now;
ans%=mod;
now=now*now;
now%=mod;
k/=2;
}
return ans;
}
ll bsgs(ll a,ll b,ll p) {
int i;
if (p%a==0) return -1;
// if (p==1) return 0;
ll m=ceil(sqrt(p));
ll l=b;
mp[l]=1;
for (i=1;i<=m;i++) {
l*=a;
l%=p;
mp[l]=i+1;
}
l=fastpower(a,m,p);ll r=l;
for (i=1;i<=m;i++) {
if (mp[r]) {
ll ans=i*m-mp[r]+1;
mp.clear();
return ans;
}
r*=l;
r%=p;
}
mp.clear();
return -1;
}
int main() {
ll p,b,n;
while (scanf("%lld%lld%lld",&p,&b,&n)!=EOF) {
ll ans=bsgs(b,n,p);
if (ans==-1) printf("no solution\n"); else
printf("%lld\n",ans);
}
return 0;
}