BSGS(大步小步)算法学习笔记

BSGS(大步小步)算法学习笔记

前置芝士

会取模运算就行啦!

正文部分

拔山盖世 BSGS\tt{BSGS} 算法用于求解 axb(modp), apa^x \equiv b \pmod{p}, \ a \perp pxx 的值。

x=tijx = ti - jt=pt = \left \lceil \sqrt{p} \right \rceil1it1 \le i \le t0j<t0 \le j < t

然后简单化一下:

atijb        atibaj(modp)a^{ti-j} \equiv b \ \ \ \ \Rightarrow \ \ \ \ a^{ti} \equiv ba^j \pmod{p}

因为 bajba^j 只有 tt 个取值,可以先枚举 jj ,求出所有的 bajba^j 并使用 Hash\tt{Hash}map\tt{map} 存储,然后枚举 ii,求出 atia^{ti},查找是否有与之相等的 bajba^j ,若有则 tijti-j 即为合法的 xx 值。不算 Hash\tt{Hash}map\tt{map} 的化,复杂度 Θ(p)\Theta(\sqrt{p})

CODE

int Pow(int x, int k, int p, int r = 1) {
	for (; k; k >>= 1, x = x * x % p) {
		if (k & 1) r = r * x % p;
	}
	return r;
}

int bsgs(int a, int b, int p) {
	b %= p, a %= p;
	map<int, int> m;
	int t = ceil(sqrt(p)), k = 1;
	for (int i = 0; i < t; i ++, k = k * a % p) {
		m[k * b % p] = i;
	}
	a = Pow(a, t, p), k = a;
	for (int i = 1; i <= t; i ++, k = k * a % p) {
		if (m.find(k) == m.end()) continue;
		if (i * t - m[k] >= 0) return i * t - m[k];
	}
	return -1;
}

exBSGS

使用 BSGS\tt{BSGS} 有一个限制条件,即 apa \perp pexBSGS\tt{exBSGS} 就是为了解决这个问题。

考虑 aapp 不互质时怎么做,设 g=gcd(a,p)g = \gcd(a,p)a=aga = a'gp=pgp=p'g,易得 :

axgxkpg=ba'^xg^x-kp'g=b

g(axgx1kp)=b\Rightarrow g \left( a'^x g^{x-1} - kp'\right) = b

gb\Rightarrow g \mid b

得到有解的条件:gbg \mid b。 然后继续瞎搞一波:

axb(modp)a^x \equiv b \pmod{p}

axgbg(modp)\Rightarrow \dfrac{a^x}{g} \equiv \dfrac{b}{g} \pmod{p'}

a×ax1bg(modp)\Rightarrow a' \times a^{x -1} \equiv \dfrac{b}{g} \pmod{p'}

ax1bg×a1(modp)\Rightarrow a^{x-1} \equiv \dfrac{b}{g} \times a'^{-1} \pmod{p'}

每次使 $b = \dfrac{b}{g} \times a’^{-1} p = p’$,缩小问题范围,一直做到 aapp 互质即可 BSGS\tt{BSGS} 求解。注意 aa 的指数变为 x1x-1

CODE

int Pow(int x, int k, int p, int r = 1) {
	for (; k; k >>= 1, x = x * x % p) {
		if (k & 1) r = r * x % p;
	}
	return r;
}

void exgcd(int a, int b, int &x, int &y) {
	if (b == 0) {x = 1, y = 0; return;};
	exgcd(b, a % b, x, y);
    int t = y; y = x - (a / b) * y, x = t;
}

int Inv(int x, int p, int a = 0, int b = 0) {
	return exgcd(x, p, a, b), (a % p + p) % p;
}

int gcd(int a, int b) {
	return (!b ? a : gcd(b, a % b));
}

int bsgs(int a, int b, int p) {
	b %= p, a %= p;
	map<int, int> m;
	int t = ceil(sqrt(p)), k = 1;
	for (int i = 0; i < t; i ++, k = k * a % p) {
		m[k * b % p] = i;
	}
	a = Pow(a, t, p), k = a;
	for (int i = 1; i <= t; i ++, k = k * a % p) {
		if (m.find(k) == m.end()) continue;
		if (i * t - m[k] >= 0) return i * t - m[k];
	}
	return -1;
}

int exbsgs(int a, int b, int p) {
	b %= p, a %= p;
	if(b == 1 || p == 1)return 0;
	int g = gcd(a, p), s = 0, c = 1;
	for (; g > 1; g = gcd(a, p)) {
		if (b % g != 0) return -1;
		b /= g, p /= g, (c *= a / g) %= p, s ++;
		if (b == c) return s;
	}
	int res = bsgs(a, b * Inv(c, p), p);
	return (~res ? res + s : res);
}

参考OI Wikihttps://mancityfc.blog.luogu.org/solution-p3846cqh’s blog


BSGS(大步小步)算法学习笔记
https://ybwa.github.io/p/17d3f61c/
作者
yb
发布于
2021年11月4日
许可协议