关于 BSGS 以及 ExBSGS 算法的理解

BSGS

引入

求解关于\(X\)的方程,

\[A^X\equiv B \pmod P \]

其中\(Gcd(A,P)=1\)

求解

我们令\(X=i*\sqrt{P}-j\),其中\(0<=i,j<=\sqrt{P}\)
则原式可以变为:

\[A^X\equiv B \pmod P \]

\[A^{i*\sqrt{P}-j}\equiv B \pmod P \]

由于\(Gcd(A,P)=1\),则可以恒等变化为:

\[A^{i*\sqrt{P}}\equiv B*A^j \pmod P \]

则我们可以先预处理出所有的\(A^{i*\sqrt{P}}\),存入哈希表。
再枚举\(B*A^j\),在哈希表里查找即可得解。

代码

int quick_Pow(int x,int y,int p){
	if(y==0)return 1;
	if(y==1)return x;
	if(y%2)return 1ll*x*quick_Pow(1ll*x*x%p,y/2,p)%p;
	return quick_Pow(1ll*x*x%p,y/2,p);
}
void BSGS(int x,int y,int p){
	x%=p;y%=p;
	if(x==0&&y!=0){puts("-1");return ;}
	if(x==0&&y==0){puts("1");return ;}
	if(y==1){puts("0");return ;}
	int st=int(sqrt(p))+1;Mp.clear();
	for(int i=1,rt=1;i<=st;i++,rt=(1ll*rt*x)%p)Mp[rt]=i;
	int sum=quick_Pow(x,st,p);
	for(int i=1,rt=1;i<=st;i++){
		rt=(1ll*rt*sum)%p;
		if(Mp[rt]){
			printf("%d\n",i*st-Mp[rt]);
			return ;
		}
	}
	puts("-1");
}

ExBSGS

引入

求解关于\(X\)的方程,

\[A^X\equiv B \pmod P \]

其中\(Gcd(A,P)\)无特殊条件。

由于\(Gcd(A,P)\)可能不为\(1\),所以\(A\)关于\(P\)可能没有逆元。
故不能用一般的 BSGS 求解。

求解

我们设\(D=Gcd(A,P)\)
则显然有 \(\frac{A}{D}\equiv 1\pmod P\)
则原式$$A^X\equiv B \pmod P$$
可恒等变形为$$A^{X-1}\cdot\frac{A}{D}\equiv \frac{B}{D} \pmod {\frac{P}{D}}$$
而由于\(Gcd(\frac{A}{D},\frac{P}{D})=1\),则有

\[A^{X-1}\equiv \frac{B}{D}\cdot({\frac{A}{D}})^{-1} \pmod {\frac{P}{D}} \]

则此时\(\frac{P}{D}\)就相当于新的\(P\)值,\(\frac{B}{D}\cdot({\frac{A}{D}})^{-1}\)就相当于新的\(B\)值,
就可以这样递推下去了。(注:下一次的\(D\)是新的\(P\)值与\(A\)\(Gcd\)

考虑边界状态:
①:若当前的\(D=1\),则问题转化为普通的 BSGS。
②:若\(B\)值等于\(1\)了,则迭代到的\(Ans\)值为\(1\)
③:若\(D \nmid B\),即\(D\)不是\(B\)的因数,则\(\frac{B}{D}\)没有意义,则无解。

综上,出解。

例题及代码

板题
题意:求满足\(A^X\equiv B \pmod{P}\)的最小整数\(X\)

#include<map>
#include<cmath>
#include<cstdio>
#include<algorithm>
#include<tr1/unordered_map>
using namespace std;
#define LL long long
tr1::unordered_map<LL,int>Mp;
LL Gcd(LL x,LL y){
	if(x==0)return y;
	return Gcd(y%x,x);
}
LL quick_Pow(LL x,LL y,LL p){
	if(y==0)return 1;
	if(y==1)return x;
	if(y%2)return x*quick_Pow(x*x%p,y/2,p)%p;
	return quick_Pow(x*x%p,y/2,p);
}
int ExBSGS(int x,int y,int p){
	if(y==1)return 0;//特判解为0的情况.
	LL k=0,a=1;
	while(1){
		int d=Gcd(x,p);if(d==1)break;
		if(y%d)return -1;
		y/=d;p/=d;k++;a=(1ll*a*x/d)%p;
		if(a==y)return k;//同特判.
	}Mp.clear();
	LL st=int(sqrt(p))+1,sum=quick_Pow(x,st,p);
	for(LL i=0,rt=y;i<=st;i++,rt=(1ll*rt*x)%p)Mp[rt]=i+1;
	for(LL i=1,rt=(a*sum)%p;i<=st;i++,rt=(1ll*rt*sum)%p){//不将求解中的A/D移项.
		if(!Mp[rt])continue;
		return 1ll*i*st-(Mp[rt]-1)+k;
	}
	return -1;
}
int A,B,C;
int main(){
	while(~scanf("%d%d%d",&A,&B,&C)&&A){
		int Ans=ExBSGS(A,C,B);
		if(Ans!=-1)printf("%d\n",Ans);
		else puts("Orz,I can’t find D!");
	}
}

注:一般的,题目所给的A,B,C都是正整数。

posted @ 2019-10-04 08:50  孤攀客  阅读(232)  评论(0编辑  收藏  举报