BSGS&exBSGS(让你轻松理解和掌握)

BSGS(Baby step Giant step)

BSGS(Baby step Giant step)简称,拔山盖世,不是个事,哈哈哈,不开玩笑了,它的名字叫大步小步算法,主要用来解决形如 a x a^x ax b b b(mod p)的高次线性同余方程==,其中a,p互质,求最小正整数解x的问题

解题步骤如下:
step1.令m=ceil( p \sqrt p p ),也就是对p开二次根号然后向上取整。

step2.令 x = i ∗ m − j x=i*m-j x=imj,1<=i<=m,0<=j<=m-1,此时原式可以表示为 a i ∗ m − j a^{i*m - j} aimj≡b(mod p) -> a i ∗ m a^{i*m} aim b × a j b×a^j b×aj(mod p)。

step3.我们把等式右边 b × a j b×a^j b×aj,(0<=j<=m-1)的结果存入哈希表,
其中键为 b × a j b×a^j b×aj,值为j,如果键有重复出现,那么用j值大的覆盖j值小的,因为 x = i ∗ m − j x=i*m-j x=imj,j越大,x越小。

step4.在枚举左边的i,如果 a i ∗ m a^{i*m} aim能在哈希表中找到,那么最小正整数x就是此时的 i ∗ m − j i*m-j imj

如果遍历完i都找不到对应的j值的话,说明无解

模板代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
unordered_map<ll, ll>mp;
/*快速幂*/
ll quik_pow(ll dishu,ll zhishu,ll mod)
{
	ll ans=1;
	while(zhishu)
	{
		if(zhishu&1)
		{
			ans=ans*dishu%mod;
			zhishu--;
		}
		else
		{
			dishu=dishu*dishu%mod;
			zhishu>>=1;
		}
	}
	return ans;
}
int main()
{
	ll p,b,n;
	cin>>p>>b>>n;
	ll m = ceil(sqrt(p));//第一步对模p开二次根号向上取整
	/*第二步,遍历等式右边的j从0到m-1,把答案存入哈希表*/
	for(ll j=0;j<m;j++)
	{
		ll number = quik_pow(b,j,p);
		ll ans = n%p*number%p;
		mp[ans]=j; 
	}
	/*第三步,遍历等式左边的i值从1到m,如果找到对应的j值输出答案*/
	for(ll i=1;i<=m;i++)
    {
        ll ans = quik_pow(b,i*m,p);
        if(mp.count(ans)!=0)
        {
        	cout<<i*m-mp[ans];
        	return 0;
		}
	}
	/*遍历完i值之后都找不到一个j值说明此时无解*/
	cout<<"no solution";
	return 0;
}

来一道模板题练练手P3846 [TJOI2007] 可爱的质数/【模板】BSGSAC代码就是上面的模板

EXBSGS(Extend Baby step Giant step)

那么问题来了,BSGS只适用于 a x ≡ b ( m o d p ) a^x≡b(mod p) axb(modp),a,p互质的情况,那么如果a,p不互质呢?,这时候就需要用到扩展BSGS算法
思路:如果a,p不互质,那么我们就想方法让它们互质,想必你一定是一头雾水,下面我们就用迭代的思想,来解决这个问题

推导:
a^x≡b(mod p),等价于 a x + p y = b a^x+py=b ax+py=b,我们令g1=gcd(a,p),那么 a ( x − 1 ) ∗ a / g 1 + p ∗ y / g 1 = b / g 1 a^{(x-1)}*a/g1+p*y/g1 = b/g1 a(x1)a/g1+py/g1=b/g1,显然迭代过程中要判断b是否能整除gcd(a,p)这里是g1,如果不能那么说明无解
此时 a ( x − n ) ∗ a / g 1 ≡ b / g 1 a^{(x-n)}*a/g1≡b/g1 a(xn)a/g1b/g1(mod p/g1),--------①
不妨写成 a ( x − n ) ∗ D n ≡ b n a^{(x-n)}*Dn ≡ bn a(xn)Dnbn (mod pn), --------②
等价于 a ( x − n ) ≡ b n ∗ D n − 1 a^{(x-n)}≡bn* Dn^{-1} a(xn)bnDn1(mod pn),-------③
n是迭代次数
这时候判断a与pn是否互质,如果不互质,按照上面的方法继续迭代,直到互质或者Dn=bn,由②式我们知道,迭代过程中如果Dn=bn,原式就等价于 a ( x − n ) ≡ 1 a^{(x-n)}≡1 a(xn)1(mod pn),也即②式两边同除Dn,此时解为x0=0=x-n,所以原方程的解x为x=x0+n=n

迭代到最后

a ( x − n ) ∗ D n ≡ b n a^{(x-n)}*Dn≡bn a(xn)Dnbn(mod pn),a,pn互质
D n = ∏ i = 1 n a g i Dn = \prod_{i=1}^{n} \frac{a}{gi} Dn=i=1ngia
b n = b ∏ i = 1 n g i bn = \frac{b}{\prod_{i=1}^{n}gi} bn=i=1ngib
p n = p ∏ i = 1 n g i pn = \frac{p}{\prod_{i=1}^{n}gi} pn=i=1ngip

然后解出最后迭代出来的方程的解x0=x-n,正解即为x=x0+n(n是迭代次数)
当然在解 a x ≡ b a^x≡b axb(mod p),a,p不互质的方程的时候,是要分情况讨论的
①a=0,若b≠0,则无解,如果b=0,那么x=1

②若b=1,那么x=0

③b=0,且a≠0,那么使用exbsgs迭代,使得pn为1,这样 a ( x − n ) ∗ D n ≡ 0 a^{(x-n)}*Dn≡0 a(xn)Dn0(mod 1)才有解,如果迭代不能使pn为1,那么无解

④a≠0,且b≠0,那么按照上述常规exbsgs解法解题即可

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
unordered_map<ll, ll>mp;
ll P;
ll ksm(ll dishu,ll zhishu)
{
	ll ans=1;
    while(zhishu)
    {
    	if(zhishu&1)
    	{
    		ans=ans*dishu%P;
    		zhishu--;
		}
		else{
			dishu=dishu*dishu%P;
			zhishu>>=1;
		}
	}
	return ans;
}
void exbsgs(ll A,ll B)
{
	if(A==0)
	{
		if(B==0)
		{
		 printf("1\n");
	     return ;
		}
		else
		{
			printf("No Solution\n");
			return ;
		}
	}
	if(B==1)
	{
		printf("0\n");
		return ;
	}
	if(B==0)
	{
		int count=0;
		ll d=__gcd(A,P);
		while(d!=1)
		{
			count++;
			P/=d;
			if(P==1)
			{
				printf("%d\n",count);
				return ;
			}
			d=__gcd(A,P);
		}
	}
    if(B==1)
    {
    	printf("0\n");
    	return ;
	}
	ll count=0;
	ll k=1;
	ll d=__gcd(A,P);
	while(d!=1)
	{
		if(B%d)
		{
			printf("No Solution\n");
			return ;
        }
        P/=d,B/=d;k=k*(A/d)%P;
        count++;
        if(B==k)
        {
        	printf("%lld\n",count);
        	return ;
		}
		d=__gcd(A,P);
	}
	ll m=ceil(sqrt(P));
	ll s=B;
	mp.clear();
	for(int j=0;j<m;j++)
	{
		mp[s]=j;
		s=s*A%P;
	}
    s=k;
	k=ksm(A,m);
	for(int i=1;i<=m;i++)
	{
		s=s*k%P;
		if(mp[s])
		{
			printf("%lld\n",i*m-mp[s]+count);
			return ;
		}
	}
	printf("No Solution\n");
	return ;
}
int main()
{
	ll A,B;
	cin>>A>>P>>B;
    while(A&&B&&P)
    {
    	exbsgs(A,B);
    	cin>>A>>P>>B;
	}
	return 0;
}

来一道exgsbs模板题练练手P4195 【模板】扩展BSGSAC代码就是上面的模板

如果鄙人的博客能够让你有哪怕一点点的收获,都是鄙人最大的荣幸,鄙人厚着脸皮向您讨个点赞,谢谢。

  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值