BSGS
\(BSGS\)
\(BSGS\)(\(baby-step\space giant-step\)),即大步小步算法,常用于求解离散对数问题。
形式化地说,该算法可以在 \(O(\sqrt{p})\) 的时间内求解 \(a^x \equiv b \pmod p\) (\(a\perp p\)) 方程的解 \(x\) 满足 \(0 \le x < p\)。(在这里需要注意,只要 \(a\perp p\) 就行了,不要求 \(p\) 是素数)
\(BSGS\)
令 \(t=\lceil \sqrt p \rceil\),\(x = i\cdot t- j\),其中 \(0\le i,j \le t\),则有 \(a^{i\cdot t -j} \equiv b \pmod p\),变换得 \(a^{i\cdot t} \equiv b\cdot a^j \pmod p\)
先枚举\(j\),算出等式右边的 \(b\cdot a^j\) 的所有取值,然后枚举\(i\),计算 \(a^{i\cdot t}\),看是否有与之相等的 \(b\cdot a^j\),从而得到 \(x\)
由于 \(0\le i,j \le t=\lceil \sqrt p \rceil\),所以复杂度为\(O(\sqrt{p})\)
il int bsgs(int a,int b,int p){
if(1%p==b%p) return 0;
int t=ceil(sqrt(p)),s=1,ss=0;
mp.clear();
for(ri int i=0;i<t;++i){
if(s==b) return i; // a^0=1
mp[s*b%p]=i,s=s*a%p;
}
ss=s;
for(ri int i=1;i<=t;++i){
if(mp.count(ss)) return i*t-mp[ss];
ss=ss*s%p;
}
return -1;
}
\(exBSGS\)
对于\(a^x \equiv b \pmod p\),\(a,p\)不一定互质,在模 \(p\) 意义下 \(a\) 不一定存在逆元,于是我们想办法让他们变得互质
我们设 \(d_1=\gcd(a,p)\),如果 \(d_1\nmid b\),则原方程无解。否则我们把方程同时除以 \(d_1\),得到
如果\(a\not\perp \frac{p}{d_1}\),就继续除,设 \(d_2=\gcd\left(a,\frac{p}{d_1}\right)\) ,如果 \(d_2\nmid \frac{b}{d_1}\),则方程无解;否则同时除以 \(d_2\) 得到
重复上述操作,直到\(a\perp \frac{p}{d_1\cdot d_2 \dots d_k}\)
il int exbsgs(int a,int b,int p){
int d=1,nxtd=0,as=0,xi=1%p,k=0;
while(1){
nxtd=gcd(xi*a%p,p);
if(d==nxtd) break;
if(xi==b) return k;
++k,xi=xi*a%p,d=nxtd;
}
if(b%d) return -1;
xi/=d,p/=d,b/=d;
b=b*inv(xi,p)%p,as=bsgs(a,b,p);
return (~as)?k+as:as;
}