[BZOJ 2480] [SPOJ 3105] Mod

Description

已知数 (a,p,b),求满足 (a^xequiv bpmod p) 的最小自然数 (x)

Input

每个测试文件中最多包含 (100) 组测试数据。

每组数据中,每行包含 (3) 个正整数 (a,p,b)

(a=p=b=0) 时,表示测试数据读入完全。

Output

对于每组数据,输出一行。

如果无解,输出“No Solution”(不含引号),否则输出最小自然数解。

Sample Input

5 58 33
2 4 3
0 0 0

Sample Output

9
No Solution

HINT

(a,p,b≤10^9)

Solution

(gcd(a,q) otmid b)(b e 1) 时无解。

[a^xequiv bpmod p\ a^{x-1}frac{a}{(a,p)}equiv frac{b}{(a,p)}pmod{frac{p}{(a,p)}} ]

注意这里不能写成 (a^{x-1}equiv b imes a^{-1}pmod{frac{p}{(a,p)}}),因为此时 (a otperp p),没有逆元。

递归求解,直到 (aperp p),此时式子的形式是

[k imes(a^m)^iequiv a^jbpmod p ]

(0dots m) 枚举 (j),将 (a^jb) 的值存入 (hash) 表中,然后从 (1dots m) 枚举 (i),若表中存在 (k imes (a^m)^i),则当前 (i imes m-j) 就是答案。

Code

#include <cmath>
#include <cstdio>
#include <tr1/unordered_map>

std::tr1::unordered_map<int,int> hash;

int read() {
	int x = 0; char c = getchar();
	while (c < '0' || c > '9') c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar();
	return x;
}
int gcd(int a, int b) {
	return b ? gcd(b, a % b) : a;
}
void exbsgs(int a, int b, int p) {
	if (p == 1 || b == 1) { puts("0"); return; }
	int t = gcd(a, p), k = 0, c = 1;
	while (t > 1) {
		if (b % t) { puts("No Solution"); return; }
		b /= t, p /= t, c = 1LL * c * a / t % p, t = gcd(a, p), ++k;
		if (b == c) { printf("%d
", k); return; }
	}
	int m = ceil(sqrt(p)); hash.clear(), hash[b] = 0;
	for (int i = 1; i <= m; ++i) t = 1LL * t * a % p, hash[1LL * t * b % p] = i;
	a = t, t = 1LL * t * c % p;
	for (int i = 1; i <= m; ++i, t = 1LL * t * a % p)
		if (hash.count(t)) { printf("%d
", i * m - hash[t] + k); return; }
	puts("No Solution");
}
int main() {
	int a = read(), p = read(), b = read();
	while (a) exbsgs(a % p, b % p, p), a = read(), p = read(), b = read();
	return 0;
}
A man can be destroyed, but not defeated.
原文地址:https://www.cnblogs.com/fly-in-milkyway/p/10322542.html