bsgs

bsgs,北上广深,拔山盖世,蓝超巨星(blue super giant star)。大概是\(O(\sqrt n)\)求解模意义下离散对数的一个算法。经典的平衡复杂度思想。
本质是根号分治。

离散对数,也就是长这样的一个东西:

\[a^x\equiv b\pmod p \]

其中\(p\)是个质数,给你\(a,b,p,\)求最小的正整数\(x\)

首先我们根据费马小定理知道\(a^x\)是个循环的,而且一个循环节是\(p-1\)。当然不一定是最小循环节。当然,我们不能暴力搞。这时我们就用到了一个重要思想:平衡复杂度的思想。

具体的,我们随便设个\(t\)(先在这挂着,取值一会再说),然后开始导柿子:

\[a^x\equiv b \pmod p \]

\(x=i\cdot t-j\)

\[a^{i\cdot t-j}\equiv b \pmod p \]

\[a^{i\cdot t}\equiv b\cdot a^j \pmod p \]

对这个柿子,我们可以预处理每个\(a^j\),然后枚举\(i\)来找。显然\(j<t\)。当\(t=\sqrt n\)时,复杂度最低,为\(O(\sqrt n)\)

知道原理之后代码其实很好写。

unordered_map<int,int>mp;
int bsgs(int a,int b){
	mp.clear();
	int sq=sqrt(mod)+1;
	int tmp=b;
	for(int i=0;i<sq;i++){
		mp[tmp]=i;//先预处理所有的j放到哈希表里 
		tmp=1ll*tmp*a%mod;
	}
	a=qpow(a,sq);
	if(!a)return b==0?1:-1;//特判一下有无解 
	for(int i=1,val=1;i<=sq;i++){//枚举所有i 
		val=1ll*val*a%mod;
		if(mp.find(val)!=mp.end())return i*sq-mp[val];//查找能不能找到对应的j 
	}
	return -1;
}

然后是 exbsgs,用于 \(a,p\) 不互质的情况。设 \(d=\gcd(a,p)\),则

\[a^x\equiv b\pmod p \]

可以变成

\[\frac{a^x}d\equiv \frac bd\pmod {\frac pd} \]

换个写法:

\[\frac ada^{x-1}\equiv \frac bd\pmod {\frac pd} \]

如果 \(d\not|\ b\) 则无解。然后一直消掉 \(d\),直到 \(a,p\) 互质,跑遍 bsgs 再加上消的次数即可。

int exbsgs(int a,int b,int mod){
    if(b==1||mod==1)return 0;
    int d=gcd(a,mod),k=0,mul=1;
    while(d!=1){
        if(b%d!=0)return -1;
        k++;b/=d;mod/=d;mul=1ll*mul*(a/d)%mod;
        if(mul==b)return k;
        d=gcd(a,mod);
    }
    int f=bsgs(a,1ll*b*inv(mul,mod)%mod,mod);
    if(f==-1)return -1;
    return f+k;
}
posted @ 2022-09-03 19:30  gtm1514  阅读(59)  评论(0编辑  收藏  举报