【bzoj3239】Discrete Logging BSGS
题目描述
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
B
L
== N (mod P)
输入
Read several lines of input, each containing P,B,N separated by a space,
输出
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) .
样例输入
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
样例输出
0
1
3
2
0
3
1
2
0
no solution
no solution
1
9584351
462803587
题目大意
求关于L的方程B^L≡N(mod P)的最小非负整数解,无解则输出no solution,其中P是质数。
题解
裸的BSGS,参见 bzoj2242
#include <cstdio> #include <cmath> #include <map> using namespace std; typedef long long ll; map<ll , ll> f; map<ll , ll>::iterator it; ll pow(ll x , ll y , ll mod) { ll ans = 1; while(y) { if(y & 1) ans = ans * x % mod; x = x * x % mod , y >>= 1; } return ans; } int main() { ll p , b , n; while(scanf("%lld%lld%lld" , &p , &b , &n) != EOF) { ll m = (ll)ceil(sqrt(p)) , i , t , temp , flag = 0; f.clear(); for(t = 1 , i = 0 ; i < m ; t = t * b % p , i ++ ) if(f.find(t) == f.end()) f[t] = i; for(t = 1 , temp = pow(b , p - m - 1 , p) , i = 0 ; i < m ; t = t * temp % p , i ++ ) { it = f.find(n * t % p); if(it != f.end()) { printf("%lld\n" , i * m + it->second) , flag = 1; break; } } if(!flag) printf("no solution\n"); } return 0; }