bsgs(大步小步算法)和exbsgs(扩展大步小步算法)学习小记

本文详细介绍了解决模指数方程的Baby-step Giant-step (BSGS)算法及其扩展版本exBSGS。主要内容包括算法的基本原理、步骤解析及应用实例,特别针对质数模和合数模的情况给出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

翻译:

bsgs:
baby steps,giant steps

bsgs:

解决以下问题:
有三个整数a,b,p,其中p是质数。

求最小的自然数x,使ax=b(mod p)a^x=b(mod~p)ax=b(mod p)

根据费马小定理,ap−1=1(mod p)a^{p-1}=1(mod~p)ap1=1(mod p),所以只用考虑x=0~p-1

m=pm=\sqrt pm=p,则x可以表示成i∗m+j(0&lt;=i,j&lt;m)i*m+j(0&lt;=i,j&lt;m)im+j(0<=i,j<m)

ax=b(mod p)a^{x}=b(mod~p)ax=b(mod p)
ai∗m+j=b(mod p)a^{i*m+j}=b(mod~p)aim+j=b(mod p)
b∗a−j=ai∗m(mod p)b*a^{-j}=a^{i*m}(mod ~p)baj=aim(mod p)

于是容易想到枚举jjj,用个hash表存一下b∗a−jb*a^{-j}baj

接着枚举iii,判断hash表里有没有ai∗ma^{i*m}aim就行了。


补充2019.3.7

我们发现求逆元的话在p是质数的情况下还不算麻烦,但是对于exbsgs的话写一个exgcd显然是不划算的。

那么我们可以这么做:
m=⌈n ⌉m=\lceil \sqrt n~\rceilm=n 
ax=ba^x=bax=b可以写成ax∗m−y=b(x,y&lt;=m)a^{x*m-y}=b(x,y&lt;=m)axmy=b(x,y<=m)
ax∗m=ay∗ba^{x*m}=a^y*baxm=ayb,这样就不用逆元了。


裸题:
【SDOI2011】计算器

Code不放了,与exbsgs类似。

exbsgs:

p不是质数。

ax=b(mod p)a^{x}=b(mod ~p)ax=b(mod p)

d=gcd(a,p)d=gcd(a, p)d=gcd(a,p)

此时如果b不是d的倍数且b≠1,无解,如果b=1,x=0。

可以改写成:
ax−1∗ad=bd(mod pd)a^{x-1}*{a \over d}={b \over d}(mod ~{p \over d})ax1da=db(mod dp)

此时a可能与pd{p \over d}dp还不互质,那就一直取gcd,设取了k次,则最后式子是:
ax−k∗ak∏di=b∏di(mod p∏di)a^{x-k}*{a^k\over \prod d_i}={b \over\prod d_i }(mod~{p \over \prod d_i})axkdiak=dib(mod dip)

此时互质了,直接套用bsgs,答案加个k就行了。

但是要注意一下x&lt;&lt;<k的情况,这个在之前的试除就可以判掉。

Code(【SDOI2011】计算器):

裸题:
SPOJ MOD

Code:

#include<cstdio>
#include<cmath>
#include<map>
#define ll long long 
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
using namespace std;

ll a, b, p;

ll ksm(ll x, ll y, const ll mo) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

ll gcd(ll x ,ll y) {
	return !y ? x : gcd(y, x % y);
}

map<ll, ll> h;

ll exbsgs(ll a, ll b, ll p) {
	if(b == 1) return 0;
	ll k = 0, d = 1, t;
	while((t = gcd(a, p)) != 1) {
		if(b % t) return -1;
		k ++, b /= t, p /= t, d = d * (a / t) % p;
		if(b == d) return k;
	}
	h.clear();
	ll m = sqrt(p * 1.0)+1, a_m = ksm(a, m, p);
	ll mul = b;
	fo(j, 1, m) {
		mul = mul * a % p;
		h[mul] = j;
	}
	fo(i, 1, m) {
		d = d * a_m % p;
		if(h[d]) return i * m - h[d] + k;
	}
	return -1;
}

int main() {
	while(1) {
		scanf("%lld %lld %lld", &a, &p, &b);
		if(a == 0 && b == 0 && p == 0) return 0;
		ll ans = exbsgs(a, b, p);
		if(ans == -1) printf("No Solution\n"); else printf("%lld\n", ans);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值