大步小步算法学习笔记

一、BSGS 算法

系统来说,它适用于求离散对数,也就是高次同余方程的解。

给定一个整数 \(p\),以及一个整数 \(b\),一个整数 \(n\),现在要求你计算一个最小的非负整数 \(l\),满足 \(b^l \equiv n \pmod p\)\(2\le b,n < p<2^{31},\gcd(p,b)=1\)

首先,我们发现 \(l\in [0,p-1]\),而且所有 \(i\in[0,p-1],b^i\) 不具有单调性,而且有可能所有 \(i\in[0,p-1],b^i\) 互不相同。所以有一个朴素做法:计算出所有的 \(i\in[0,p-1],b^i\)。时间复杂度 \(O(p)\),不能通过此题。

考虑用哈希处理。我们将 \(p\) 分成若干块。首先我们令 \(s\)\(\lceil\sqrt p\rceil\),预处理出 \(b^0,b^1,…,b^{s-1}\) 的所有值,扔进一个哈希表 \(a\) 里。然后对于 \(\forall i\in [0,p-1]\),一定可以表示为 \(i=u\times s+v\),其中 \(u,v\in [0,s-1]\),所以 \(b^i=(b^s)^u\times b^v\)。那么我们把所有的 \(b^v\) 扔进了 \(a\),再枚举 \(u\) 的值进行查询就可以了。

map 实现的话,时间复杂度是 \(O(\sqrt p\times \log p)\),可以通过此题。

map<ll,ll>a;
ll p,b,s,v,w=1,x=1;
int main(){
	p=read();b=read();v=read();
	s=sqrt(p)+1;
	for(ll i=0;i<s;i++){
		if(!a[v])a[v]=i+1;
		v=v*b%p;x=x*b%p;
	}
	for(ll i=1;i<=s;i++){
		w=w*x%p;
		if(a[w]){
			cout<<i*s-a[w]+1<<'\n';
			return 0;
		}
	}
	cout<<"no solution\n";
	return 0;
}

当然更优复杂度是用 gp_hash_table 实现的,时间复杂度 \(O(\sqrt p)\)

#include<ext/pb_ds/assoc_container.hpp>
using namespace __gnu_pbds;
gp_hash_table<ll,ll>a;

二、exBSGS 算法

如果 \(p\) 不一定与 \(b\) 互质怎么办?

那我们努力使得 \(b^l \equiv n \pmod p\)\(b^l\)\(p\) 互质。我们令 \(g=\gcd(b,p)\),然后我们将 \(p\) 反复除以 \(g\),使得 \(\gcd(b,p')=1\)。假设我们一共除了 \(cnt\) 次。如果在除以 \(g\) 的过程中得出了结果,直接返回。否则结果一定大于 \(cnt\)。然后我们知道如果 \(g\mid a,g\mid b,g\mid c\),那么 \(a\equiv b\pmod{c}\) 等价于 \(\frac{a}{g}\equiv \frac{b}{g}\pmod{\frac{c}{g}}\)。所以,原问题 \(b^l \equiv n \pmod p\) 可以转化为 \((\frac{b}{g})^{cnt}\times b^{l-cnt}\equiv \frac{n}{g^{cnt}}\pmod{\frac{p}{g^{cnt}}}\) 。那么我们发现原问题有解的必要条件之一是 \(g^{cnt}|n\)。然后我们得到的式子中,\((\frac{b}{g})^{cnt}\) 是一个整系数,并且 \(\gcd(b,\frac{p}{g^{cnt}})=1\),所以可以用 BSGS 求解 \(l-cnt\) 的最小值。程序里 BSGS 的 \(a,b,p,c\) 分别代表 \(b,(\frac{b}{g})^{cnt},\frac{p}{g^{cnt}},\frac{n}{g^{cnt}}\),然后 \(qwq\) 代表解,也就是 BSGS 求出来的 \(l-cnt\) 的最小值,或者 \(-1\) 代表无解。时间复杂度 \(O(\sqrt p)\)

gp_hash_table<ll,ll>q;
inline ll BSGS(ll a,ll b,ll p,ll c){
	q.clear();
	ll u=1,v=b,w=c,s=sqrt(p)+1;
	for(ll i=0;i<s;i++){
		q[v]=i+1;
		v=v*a%p;u=u*a%p;
	}
	for(ll i=1;i<=s;i++){
		w=w*u%p;
		if(q[w])return i*s-q[w]+1;
	}
	return -1;
}
inline ll exBSGS(ll a,ll b,ll p){
	a%=p;b%=p;
	if(p==1||b==1)return 0;
	ll cnt=0,g,ax=1,qwq;
	while((g=__gcd(a,p))!=1){
		if(b%g)return -1;
		p/=g;cnt++;b/=g;
		ax=ax*(a/g)%p;
		if(ax==b)return cnt;
	}
	return ((qwq=BSGS(a,b,p,ax))==-1)?-1:cnt+qwq;
}

三、例题

  1. P3846 [TJOI2007] 可爱的质数/【模板】BSGS
  2. P4195 【模板】扩展 BSGS/exBSGS
  3. P2485 [SDOI2011]计算器
  4. P3306 [SDOI2013] 随机数生成器
  5. MOD - Power Modulo Inverted
  6. P4454 [CQOI2018]破解D-H协议
  7. [ABC270G] Sequence in mod P
  8. P4884 多少个 1?
  9. P4861 按钮
posted @ 2023-05-09 17:04  lrxQwQ  阅读(23)  评论(0编辑  收藏  举报