浅谈BSGS&exBSGS

概(che)论(dan)

BSGS又称拔山盖世算法
Baby Step Giant Step
又称求离散对数
一般用于给出 a , b , p a, b, p a,b,p

a x ≡ b ( m o d p ) a^x \equiv b \pmod p axb(modp)

算法流程

比较简单,其实就是分块,小块的暴力预处理,然后一块一块跳
借用 psk011102 的图
在这里插入图片描述

大概就是这样
先丢个板子题吧:
代码实现很简单:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll p, b, n, mod;
map<ll, ll> mp;
ll qpow(ll x, int y) {
	ll ret = 1;
	for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
	return ret;
}
int BSGS(int p, int b, int n) {
	int m = sqrt(p) + 1; ll t = n; mod = p;
	for(int i = 0; i <= m; i ++, t = t * b % mod) mp[t] = i;//先把<=m的丢进map里面
	ll tt = qpow(b, m); t = tt;//每次跳m个
	if(!tt) return n == 0? 1 : -1;//特判0
	int f = 0;
	for(int i = 1; i <= m + 1; i ++, t = t * tt % mod) {
		int j = mp.find(t) == mp.end()? -1 : mp[t];
		if(j >= 0) return i * m - j;//如果找到了就返回
	}
	return -1;	
}
int main() {
	scanf("%lld%lld%lld", &p, &b, &n);
	int l = BSGS(p, b, n);
	if(l == -1) printf("no solution");
	else printf("%d ", l);
	return 0;
}

是不是很简单!!!
要注意这里必须满足 a ⊥ p a \perp p ap

如果不满足呢?

exBSGS

a , p a,p a,p不互质
先设 d = g c d ( a , p ) d=gcd(a,p) d=gcd(a,p)
1、如果 d ∤ b d∤b db,只有唯一解 x = 0 , b = 1 x=0,b=1 x=0,b=1
证明:
可以直接把式子写出来
a x ≡ b ( m o d p ) a^x \equiv b \pmod p axb(modp)
改一下
a x − 1 a + k p ≡ b ( m o d p ) a^{x-1}a+kp \equiv b \pmod p ax1a+kpb(modp)
根据裴蜀定理可得 g c d ( a , p ) ∣ b gcd(a,p)|b gcd(a,p)b
2、如果 d ∣ b d|b db
先两边除 d d d
a x − 1 × a d ≡ b d ( m o d p d ) a^{x-1} \times\frac{a}{d} \equiv \frac{b}{d} \pmod {\frac{p}{d}} ax1×dadb(moddp)

除过去
a x − 1 ≡ b d × ( a d ) − 1 ( m o d p d ) a^{x-1} \equiv \frac{b}{d} \times (\frac{a}{d})^{-1}\pmod {\frac{p}{d}} ax1db×(da)1(moddp)
板子
code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll &x, ll &y, ll a, ll b) {
	if(!b) {x = 1, y = 0; return a;};
	ll d = exgcd(y, x, b, a % b); y -= x * (a / b);
	return d;
}
ll qpow(ll x, ll y, ll mod) {
	ll ret = 1;
	for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
	return ret;
}
ll getinv(ll a, ll b) {
	ll x, y;
	exgcd(x, y, a, b);
	return (x % b + b) % b;
}
map<ll, ll> mp;
ll BSGS(ll a, ll b, ll mod) {
	mp.clear();
	int m = sqrt(mod) + 1;
	ll t = b % mod;
	for(int i = 0; i <= m; t = t * a % mod, i ++) mp[t] = i;
	a = qpow(a, m, mod); t = a;
	if(!t) return b == 0? 1 : -1;
	for(int i = 1; i <= m + 1; i ++, t = t * a % mod) {
		int j = mp.find(t) == mp.end()? -1 : mp[t];
		if(j != -1) return 1ll * i * m - j; 
	}
	return - 1;
}
ll exBSGS(ll a, ll b, ll p) {
	if(b == 1) return 0;
	ll d = 0, k = 0;
	while((d = __gcd(a, p)) != 1) {
		if(b % d) return - 1;
		++ k; p /= d, b = (b / d) * getinv((a / d), p) % p; 
		if(b == a) return k;
	}
	ll ans = BSGS(a, b, p);
	return ans == -1? -1 : ans + k;
}
ll a, b, p;
int main() {
	while(1) {
		scanf("%lld%lld%lld", &a, &p, &b);
		if(!(a || b || p)) return 0;
		ll ans = exBSGS(a, b, p);
		if(ans != -1) printf("%lld\n", ans);
		else printf("No Solution\n");
	}
	return 0;
}

posted @ 2020-08-16 21:11  lahlah  阅读(124)  评论(0编辑  收藏  举报