拓展BSGS 學習筆記
阿新 • • 發佈:2021-01-09
BSGS 演算法要求 \(a\) 和 \(p\) 互質,但如果 \(a\) 和 \(p\) 不互質怎麼辦呢?
這時候我們就引入了 \(EXBSGS\) 演算法。
還是求 \(a^x \equiv b \pmod p\) , 但 \(p\) 不一定是質數。
如果 \(a\) 和 \(p\) 互質的話,那麼套用一下 \(BSGS\) 的模板就可以解決了。
現在我們的就需要把 \(p\) 變成和 \(a\) 互質。
設 \(g = gcd(a,p)\) ,則有:
\({a\over g} a^{x-1} \equiv {b\over g} (\bmod {p\over g} )\)
如果 \(b \%\)
但如果 \(a\) 和 \(p\over g\) 互質的話,我們可以用 \(BSGS\) 演算法求出一個解來。
反之繼續遞迴下去,直到 \(a\) 和 \(p\) 互質即可。
同時在遞迴的時候,統計一下迭代的次數 \(k\),那麼最後方程的解即為 \(k + t\) ( \(t\) 為 \(BSGS\) 求出來的解)。
要注意的一點是當 \({a \over g} = b\) 的時候,這時候我們不用繼續向下遞迴下去,此時 \(x = k\) 就是原方程的一組解。
#include<iostream> #include<cstdio> #include<algorithm> #include<map> #include<cmath> using namespace std; #define int long long int a,b,p; int gcd(int a,int b) { if(b == 0) return a; else return gcd(b,a%b); } inline int read() { int s = 0,w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();} return s * w; } int ksm(int a,int b) { int res = 1; for(; b; b >>= 1) { if(b & 1) res = res * a % p; a = a * a % p; } return res; } void exgcd(int a,int b,int &x,int &y) { if(b == 0) { x = 1; y = 0; return; } exgcd(b,a%b,y,x); y -= a / b * x; } int inv(int a,int p)//求a在模p下的逆元 { int x,y; exgcd(a,p,x,y); return (x % p + p) % p; } int BSGS(int k,int a,int b,int p)//ka^x = b (mod p) { b = b * inv(k,p) % p; map<int,int> hash; int m = (int) sqrt(p) + 1; for(int i = 1; i <= m; i++) { b = b * a % p;//要一個一個的乘,否則會炸 long long hash[b] = i; } a = ksm(a,m), b = 1; for(int i = 1; i <= m; i++) { b = b * a % p; int j = hash.find(b) == hash.end() ? -1 : hash[b]; if(j >= 0 && i * m - j >= 0) return i * m - j; } return -1; } int Exbsgs(int a,int b,int p) { int k = 1, num = 0; while(gcd(a,p) != 1)//直到 a 和 p 互質可以用bsgs求出一組解來 { int g = gcd(a,p); if(b % g != 0) return -1;//無解的情況 k = k * (a/g) % p; num++;//統計迭代的次數 if(k == b) return num;//係數 k = d的時候 k就是原方程的一個解 p /= g; b /= g; } int tmp = BSGS(k,a,b,p); return tmp == -1 ? -1 : tmp + num; } signed main() { while(1) { a = read(); p = read(); b = read(); if(a == 0 && b == 0 && p == 0) break; int ans = Exbsgs(a,b,p); if(ans == -1) printf("No Solution\n"); else printf("%lld\n",ans); } return 0; }