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

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

前置芝士

会取模运算就行啦!

正文部分

拔山盖世 BSGS\tt{BSGS} 算法用于求解 ax≡b(modp), a⊥pa^x \equiv b \pmod{p}, \ a \perp p 中 xx 的值。

设 x=ti−jx = ti - j,t=⌈p⌉t = \left \lceil \sqrt{p} \right \rceil,1≤i≤t1 \le i \le t,0≤j<t0 \le j < t。

然后简单化一下:

ati−j≡b    ⇒    ati≡baj(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 ,若有则 ti−jti-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} 有一个限制条件,即 a⊥pa \perp p,exBSGS\tt{exBSGS} 就是为了解决这个问题。

考虑 aa、pp 不互质时怎么做,设 g=gcd⁡(a,p)g = \gcd(a,p),a=a′ga = a'g,p=p′gp=p'g,易得 :

a′xgx−kp′g=ba'^xg^x-kp'g=b

⇒g(a′xgx−1−kp′)=b\Rightarrow g \left( a'^x g^{x-1} - kp'\right) = b

⇒g∣b\Rightarrow g \mid b

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

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

⇒axg≡bg(modp′)\Rightarrow \dfrac{a^x}{g} \equiv \dfrac{b}{g} \pmod{p'}

⇒a′×ax−1≡bg(modp′)\Rightarrow a' \times a^{x -1} \equiv \dfrac{b}{g} \pmod{p'}

⇒ax−1≡bg×a′−1(modp′)\Rightarrow a^{x-1} \equiv \dfrac{b}{g} \times a'^{-1} \pmod{p'}

每次使 $b = \dfrac{b}{g} \times a’^{-1} ,,p = p’$,缩小问题范围,一直做到 aa,pp 互质即可 BSGS\tt{BSGS} 求解。注意 aa 的指数变为 x−1x-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 Wiki,https://mancityfc.blog.luogu.org/solution-p3846,cqh’s blog 。


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