BSGS算法求解离散对数

小步大步算法: B S G S ( B a b y   S t e p   G i a n t   S t e p ) BSGS(Baby\ Step\ Giant\ Step) BSGS(Baby Step Giant Step)

拔山盖世算法,百度搜索谷歌搜索算法

用来求解离散对数(即模意义下的对数)的算法。

给出: a x ≡ b ( m o d m ) a^x\equiv b\pmod{m} axb(modm) a , b , m a,b,m a,b,m值,( a , m a,m a,m互质),求解 x x x

由欧拉定理可知: a a a在模 m m m下有长度为 φ ( m ) \varphi(m) φ(m)的循环节。

所以朴素的暴力算法就是枚举 O ( φ ( m ) ) O(\varphi(m)) O(φ(m)),最坏情况下是 O ( m − 1 ) O(m-1) O(m1),即 m m m为素数。


B S G S BSGS BSGS就是暴力算法的优化。

记: x = A t − B x=At-B x=AtB

有: a x ≡ a A t − B ≡ b ( m o d m ) ⇒ a A t ≡ b a B ( m o d m ) a^x\equiv a^{At-B}\equiv b\pmod{m}\Rightarrow a^{At}\equiv ba^{B}\pmod{m} axaAtBb(modm)aAtbaB(modm)

B B B的取值有 φ ( m )   m o d   t \varphi(m)\bmod t φ(m)modt 个, A A A的取值有 ⌊ φ ( m ) t ⌋ \lfloor\dfrac{\varphi(m)}{t}\rfloor tφ(m)

显然是双钩函数最小值当 t = ⌈ φ ( m )   ⌉ t=\lceil\sqrt{\varphi(m)}\ \rceil t=φ(m)  是最优的。

这里为了方便直接取 t = ⌈ m   ⌉ t=\lceil\sqrt{m}\ \rceil t=m  就可以了。

然后枚举所有的 B B B对应的右式所有值,储存下来。

然后再对 A A A进行枚举当出现之前的数说明此时的 A t − B At-B AtB就是答案。


代码:

ll ksm(ll a,ll n,ll m){
	ll ans=1;
	while(n){
		if(n&1) ans=ans*a%m;
		a=a*a%m;
		n>>=1;
	}
	return ans;
}
ll BSGS(ll a,ll b,ll m){
	unordered_map<ll,ll>mp;
	ll r=b*a%m,t=sqrt(m)+1;
	for(int B=1;B<=t;B++){
		mp[r]=B;
		r=(r*a)%m;
	}
	ll at=ksm(a,t,m),l=at;
	for(int A=1;A<=t;A++){
		if(mp[l]) return A*t-mp[l];
		l=(l*at)%m; 
	}
	return -1; 
}

模板题:

P3846 [TJOI2007] 可爱的质数/【模板】BSGS

貌似数据太弱了,不用判最小也能过?

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb push_back
ll ksm(ll a,ll n,ll m){
	ll ans=1;
	while(n){
		if(n&1) ans=ans*a%m;
		a=a*a%m;
		n>>=1;
	}
	return ans;
}
ll BSGS(ll a,ll b,ll m){
	unordered_map<ll,ll>mp;
	ll r=b*a%m,t=sqrt(m)+1;
	for(int B=1;B<=t;B++){
		mp[r]=B;
		r=(r*a)%m;
	}
	ll at=ksm(a,t,m),l=at;
	ll ans=1e15;
	for(int A=1;A<=t;A++){
		if(mp[l]) return A*t-mp[l];
		l=(l*at)%m; 
	}
	return -1;
}
int main(){
	ll p,b,n;cin>>p>>b>>n;
	ll ans=BSGS(b,n,p);
	printf(ans==-1?"no solution\n":"%lld\n",ans);
	return 0;
}



扩展 B S G S BSGS BSGS待补 … … \dots\dots

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

酷酷的Herio

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值