Shank的大步小步算法(Shank‘s Baby-Step-Giant-Step Algorithm)

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <cmath>
 4 #include <map>
 5 typedef long long LL;
 6 int mul_mod(int a,int b,int n){ // a、b都小于n
 7     return a * b % n;
 8 }
 9 int pow_mod(int a,int p,int n){
10     if(p == 0) return 1;
11     LL ans = pow_mod(a,p / 2,n);
12     ans = ans * ans % n;
13     if(p % 2 == 1) ans = ans * a % n;
14     return ans;
15 }
16 // 求x和y使得ax+by=d并且|x|+|y|最小。其中d=gcd(a,b)
17 void exgcd(int a,int b,int& d,int& x,int& y){
18     if(!b) d = a,x = 1,y = 0;
19     else{
20         exgcd(b,a % b,d,y,x);
21         y -= x * (a / b);
22     }
23 }
24 // 计算模n下a的逆,如果gcd(a,n) != 1,则逆不存在,返回-1
25 int inv(int a,int n){
26     int d,x,y;
27     exgcd(a,n,d,x,y);
28     return d == 1 ? (x + n) % n : -1;
29 }
30 // 求解模方程a^x=b(mod n)。n为素数,无解时返回-1.
31 int log_mod(int a,int b,int n){
32     int m,v,e = 1,i;
33     m = (int)sqrt(n + 0.5);
34     v = inv(pow_mod(a,m,n),n); // a^m的逆v=a^(-m)
35     std::map<int,int> x; // x[j]表示满足ei(=a^i)=j的最小的i
36     x[1] = 0;
37     for(int i = 1 ; i < m ; i++){ // 计算ei
38         e = mul_mod(e,a,n);
39         if(!x.count(e)) x[e] = i;
40     }
41     // 考虑a^(im)、a^(im+1)、...、a^(im+m-1)
42     for(int i = 0 ; i < m ; i++){
43         if(x.count(b)) return i * m + x[b];
44         b = mul_mod(b,v,n);
45     }
46     return -1;
47 }
48 int main(){
49     printf("%d\n",log_mod(3,4,5));
50     return 0;
51 }

 

posted @ 2016-08-26 00:27  Yan_Bin  阅读(953)  评论(0编辑  收藏  举报