【数论】BSGS
BSGS(baby-step giant-step)
学习资料:OI Wiki
基础篇
BSGS (baby-step giant step),常用于求解离散对数问题,该算法可以在 \(\mathcal{O(\sqrt p)}\) 的时间内求解
其中 \(a\,\bot\,p\) 。方程的解 \(x\) 满足 \(0\le x<p\)。
算法描述
令 \(x=A[\sqrt p]-B\),其中 \(0\le A,B\le \lceil \sqrt p\rceil\) ,则有
稍加变换,则有
。
我们已知的是 \(a,b\),所以我们可以先算出等式右边的 \(ba^B\) 的所有取值,枚举 \(B\),用 hash / map 存下来,然后逐一计算 \(a^{A\lceil\sqrt p\rceil}\) ,枚举 \(A\) ,寻找是否有与之相等的 \(ba^B\) ,从而我们可以得到所有的 \(x\),\(x=A\lceil\sqrt p\rceil-B\) 。
注意到 \(A,B\) 均小于 \(\lceil\sqrt p\rceil\),所以时间复杂度为 \(\mathcal{Q(\sqrt p)}\),用 map 则多用一个 \(log\) 。
扩展篇
接下来我们求解
其中 \(a,p\) 不一定互质。
具体地,设 \(d_1=gcd(a,p)\) 。如果 \(d_1\nmid b\) ,则原方程误解。否则我们把方程除以 \(d_1\) ,得到
如果 \(a\) 和 \(\frac{p}{d_1}\) 仍不互质就再除,设 \(d_2=gcd(a,\frac{p}{d_1})\) 。如果 \(d_2\nmid \frac{p}{d_1}\) ,则方程无解;否则同时除以 \(d_2\) 得到
同理,这样不停判断下去直到 \(a\bot\frac{p}{d_1d_2\cdots d_k}\) 。
记 \(D=\prod^k_{i=1}d_i\) ,于是方程就变成了这样:
由于 \(a\bot \frac pD\) ,于是推出 \(\frac{a^k}D\bot\frac pD\) 。这样 \(\frac{a^k}D\) 就有逆元了,于是把它丢到方程右边,这就是一个普通的 BSGS 问题了,于是求解 \(x-k\) 后再加上 \(k\) 就是原方程的解。
注意,不排除解小于等于 \(k\) 的情况,所以在消因子之前做一下 \(\mathcal{O(k)}\) 枚举,直接验证 \(a^i\equiv b\;(mod\,p)\) ,这样就能避免这种情况。
BSGS && exBSGS 模板
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll kpow(ll a,int b,int p){
ll ans=1;
while(b){
if(b&1)ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return a;}
ll g=exgcd(b,a%b,x,y);
ll t=x;x=y;
y=t-a/b*y;
return g;
}
ll inv(ll a,ll p)//exgcd求逆元, 前提 gcd(a,p)==1
{
ll x,y;
exgcd(a,p,x,y);
x=(x+p)%p;
if(!x)x+=p;
return x;
}
map<int,int>mp;
int BSGS(ll a,ll b,ll p)// gcd(a,p)==1
{
a%=p;b%=p;
int sp=ceil(sqrt(p));
ll pa=b,ap=kpow(a,sp,p);mp.clear();
for(int i=0;i<sp;i++,pa=pa*a%p)mp[pa]=i;
pa=1;
for(int i=0,j=0;i<=sp;i++,pa=pa*ap%p,j+=sp)
if(mp.count(pa)&&j-mp[pa]>=0)return j-mp[pa];
return -1;
}
int exBSGS(ll a,ll b,ll p)
{
a%=p;b%=p;
int k=0,t;ll tp=p,tb=b,ta=1;
while((t=__gcd(a,tp))!=1){
if(tb%t)return -1;
tp/=t,tb/=t,ta=ta*a/t%tp;k++;
}
for(int i=0;i<=k;i++)
if(kpow(a,i,p)==b)return i;
tb=tb*inv(ta,tp)%tp;
return BSGS(a,tb,tp)+k;
}
int main()
{
ll a,b,p;
while(scanf("%lld%lld%lld",&a,&p,&b)&&(a||b||p))
{
int res=exBSGS(a,b,p);
if(res==-1)puts("No Solution");
else printf("%d\n",res);
}
}

浙公网安备 33010602011771号