BSGS算法简述

BSGS算法主要解决 :求a^x = b ( mod  p ) 的最小满足题意的正整数 x 的问题。

主要的解决方法是:

  将 x 分成 i * m - j,所以就变成了 a ^( i * m - j ) = b ( mod  p )

  m = ceil ( sqrt ( p ) )

  变形之后即为 ( a ^ m ) ^ i = b *  a ^ j ( mod  p )。

  在(0 -  m )范围内存下b * a ^ j 的值。

  再在 (1 - m )范围枚举,直到( a ^ m ) ^ i 存在与之配对的值,此时 x 可求。 

具体证明:

  因为 x = i*m-j , 所以x 的最大值不会超过p

  a(k mod p-1) = ak (mod p)  证明这个公式,(需要用到费马小定理)

  k mod p-1 就是 k-m(p-1) ,原式就变成了 ak-m(p-1) ≡ a(mod p)

  再变一步  a/ am(p-1) ≡ a(mod p)

  这时让 am(p-1) ≡ 1 (mod p) 就行了。

  由费马小定理知: 当p为质数且 (a,p1 时 ap-1 ≡ (mod p)

  所以推出 p 为质数 且 (a,p)=1 这个条件, 所以 a(k mod p-1) ≡ (mod p

  所以:如果枚举 x 的话枚举到 p 即可。

  所以使 imj<=p , 即 m=⌈√p⌉ , i,j 最大值也为m。

感谢 mjtcn

  代码如下:

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<map>
 5 using namespace std;
 6 typedef long long ll;
 7 const int maxn = 1e7 + 7;
 8 ll read()
 9 {
10     ll a = 0, b = 1;
11     char c = getchar();
12     while(c < '0' or c > '9')
13     {
14         if(c =='-') b = -1;
15         c = getchar();
16     }
17     while(c >= '0' and c <= '9')
18     {
19         a = a * 10 + c - '0';
20         c = getchar();
21     }
22     return a * b;
23 }
24 map <ll, int>t;
25 ll n,b,p;
26 ll quickpow(ll a, ll b)
27 {
28     ll ans = 1;
29     ll base = a;
30     while( b != 0)
31     {
32         if(b %2 == 1)
33         ans *= base;
34         b /= 2;
35         base*=base;
36         ans %= p;
37         base %= p;
38     }
39     return ans;
40 }
41 int main()
42 {
43     p = read(); b = read(); n = read();
44     //printf("%lld",quickpow(n,b));
45 /*    for(int i=1; quickpow(b,i) < maxn; i++)
46     {
47         t[quickpow(b,i)] = i;
48     }
49     for(int i=1; i * p + n < maxn; i++)
50     {
51         if(t[i*p + n])
52         printf("%lld",t[i*p + n]);
53         break;
54     }*/
55     ll m = ceil(sqrt(p));
56     if(b % p == 0)
57     {
58         printf("no solution");
59         return 0;
60     }
61     ll ret , k = 0 ;
62     ret = n % p;
63     t[ret] = 0;
64     for(int i=1; i<=m; i++)
65     {
66         ret = (ret * b) % p;
67         t[ret] = i;
68     }
69     ret = quickpow(b,m);
70     ll now = 1;
71     for(int i=1; i<=m; i++)
72     {
73         now = (now * ret) % p;
74         if(t[now]) 
75         {
76             ll ans = i * m - t[now];
77             printf("%lld",(ans % p + p) % p);
78             k = 1;
79             break;
80         }
81     }
82     if(k == 0)
83     printf("no solution");
84     return 0;
85 }
原文地址:https://www.cnblogs.com/qmcp/p/9599011.html