扩展 BSGS 学习笔记

首先你要知道什么是 BSGS。

BSGS 用于求解形如 \(a^x\equiv b\pmod p\) 的高次同余方程,其中保证 \(p\) 为质数。

根据费马小定理定理,当 \(p\) 为质数时,\(a^{p-1}\equiv 1\pmod p\)

所以当 \(x\) 有解 \(>p-1\) 时,也必然有 \(y=x-(p-1)\) 为方程的解,换言之,保证 \(0\sim p-1\) 内有解,或者无解。

\(t=\sqrt p\),假设解为 \(t\times i-j\)\(i,j\) 的取值均只有 \(t\) 种,可以事先枚举存入 Hash_Table / Map 里。

因为 \(a^{t\times i-j}\equiv b\pmod p\),所以有 \(a^{t\times i}\equiv b\times a^j\pmod p\),再次枚举 \(j\) 的取值后在之前的表中查找即可。

时间复杂度就为 \(O(\sqrt p)\),当然用 Map 带个 \(\log\)

int BSGS(int a, int b, int p){
	Hash.clear();
	int t = (int)sqrt(p) + 1;
	b %= p;
	for(int i = 0; i < t; i ++){
		int val = 1LL * b * Pow(a, i, p) % p;
		Hash.insert(val, i);
	}
	a = Pow(a, t, p);
	if(a == 0) return b == 0 ? 1 : -1;
	for(int i = 0; i <= t; i ++){
		int val = Pow(a, i, p);
		int j = Hash.find(val);
		if(j >= 0 && i * t - j >= 0) return i * t - j;
	}
	return -1;
}

扩展 BSGS,即不保证 \(p\) 为素数。

假设 \(d=\gcd(a,p)>1\),若 \(b\ {\rm mod}\ p\not = 0\),就无解。

否则因为 \(a\times d\equiv b\times d\pmod {p\times d}\) 等价于 \(a\equiv b\pmod {p}\),可以直接消去。

直到 \(a,p\) 互质,假设总共用了 \(k\)\(a\),那 \(k\)\(a\) 消去后的乘积为 \(A\),除后的 \(b,p\)\(B,P\),则问题等价于。

\(A\times a^{x-k}\equiv B\pmod P\),再转化一下变为 \(a^{x-k}\equiv B\times Inv(A,P)\pmod P\)。(\(Inv(A,P)\) 表示 \(A\)\({\rm mod}\ P\) 意义下的逆元)

这是标准的 BSGS。

模板题放这,卡常卡的人都傻掉了。

#include<bits/stdc++.h>
#define rep(i, s, t) for(int i = (s); i <= (t); i ++)
#define per(i, s, t) for(int i = (s); i >= (t); i --)
using namespace std;

#define int long long

int read() {
	int x = 0, f = 1; char c = getchar();
	while(c < '0' || c > '9') f = (c == '-') ? -1 : 1, c = getchar();
	while(c >= '0' && c <= '9') x = x * 10 + c - 48, c = getchar();
	return x * f;
}

int Gcd(int a, int b) {while(b) {int c = a; a = b, b = c % b;} return a;}

int exGcd(int a, int b, int &x, int &y) {
	if(! b) {x = 1, y = 0; return a;}
	int d = exGcd(b, a % b, x, y);
	int z = x; x = y, y = z - a / b * y;
	return d;
}

int Inv(int a, int p) {
	int x, y;
	exGcd(a, p, x, y);
	return (x % p + p) % p;
}

int Pow(int a, int b, int p) {
	int s = 1;
	for(; b; b >>= 1) {
		if(b & 1) s = 1LL * s * a % p;
		a = 1LL * a * a % p;
	}
	return s;
}

int BSGS(int a, int b, int p) {
	map<int, int> hash;
	a %= p, b %= p;
	int t = sqrt(p) + 1, c = Pow(a, t, p), d = 1;
	rep(i, 1, t) {
		d = 1LL * d * c % p;
		if(hash.find(d) == hash.end()) hash[d] = i;
	}
	int ans = 1e15;
	rep(i, 0, t) {
		if(hash.find(b) != hash.end()) ans = min(ans, t * hash[b] - i);
		b = 1LL * b * a % p;
	}
	return (ans == 1e15) ? -1 : ans;
}

int exBSGS(int a, int b, int p) {
	a %= p, b %= p;
	if(1 % p == b % p) return 0;
	int d, D = 1, c = 0;
	while((d = Gcd(a, p)) > 1) {
		if(b % d != 0) return - 1;
		b /= d, p /= d;
		D = 1LL * D * (a / d) % p, c ++;
		if(D == b) return c;
	}
	b = 1LL * b * Inv(D, p) % p;
	int ans = BSGS(a, b, p);
	if(ans == -1) return -1;
	return ans + c;
}

signed main() {
	while(true) {
		int a = read(), p = read(), b = read();
		if(! a) break;
		int ans = exBSGS(a, b, p);
		if(ans == - 1) puts("No Solution"); else printf("%d\n", ans);
	}
	return 0;
}
posted @ 2021-06-01 09:55  LPF'sBlog  阅读(143)  评论(0编辑  收藏  举报