51nod1038 X^A Mod P 原根+BSGS

版权声明:本文是蒟蒻写的,转载。。。随便吧 https://blog.csdn.net/xgc_woker/article/details/85638510

Description
X A m o d P = B X^A mod P = B ,其中 P P 为质数。给出 P P A A B B ,求 < P < P 的所有 X X
例如: P = 11 A = 3 B = 5 P = 11,A = 3,B = 5
3 3 M o d 11 = 5 3^3 Mod 11 = 5
所有数据中,解的数量不超过 S q r t ( P ) Sqrt(P)


Sample Input
3
11 3 5
13 3 1
13 2 2


Sample Output
3
1 3 9
No Solution


很久以前就做了这道题,一直没有写博客,今天写主要是怕以后忘记。

有关原根:
定义:设 g g P P 的原根那么与 P P 互质的数,都可以由 g g 为底数的次幂表示出来。
一个数有原根,当且仅当这个数为: P = 1 , 2 , 4 , p a , 2 p a P=1,2,4,p^a,2p^a
一个数 P P ,它的原根数量为 p h i ( p h i ( P ) ) phi(phi(P))
最小的原根一般比较小,于是我们考虑暴力枚举。
判断一个数 g g 是否是 P P 的原根:
1. 1. 暴力枚举。
2. 2. ( P 1 ) (P-1) 的约数中有一个质数满足 g ( P 1 ) / p i = = 1 ( m o d P ) g^{(P-1)/pi}==1(mod P)
放个结论,逃~

说到这道题:
式子是这样的:
X A = B ( m o d P ) X^A =B(mod P)
你设 g t 1 = X ( m o d P ) g^{t1}=X(modP) g t 2 = B ( m o d P ) g^{t2}=B(modP)
那么式子就是这样的:
g t 1 A = g t 2 ( m o d P ) g^{t1A}=g^{t2}(modP)
所以: t 1 A = t 2 ( m o d P 1 ) t1A=t2(mod P-1)


#include <cmath>
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int mod = 1000007;

int plen, cnt;
LL o[110000];
LL head[1100000], num[110000], id[110000], next[110000];
vector<LL> a;

LL pow_mod(LL x, LL k, LL mod) {
	LL ans = 1; x %= mod;
	while(k) {
		if(k % 2 == 1) (ans *= x) %= mod;
		(x *= x) %= mod; k /= 2;
	} return ans;
}

int Find(LL x) {
	LL y = x - 1;
	for(int i = 2; i * i <= x; i++) {
		if(y % i == 0) {
			a.push_back(i);
			while(y % i == 0) y /= i;
		}
	} if(y > 1) a.push_back(y);
	int o;
	for(int i = 1; ;i++) {
		bool bk = 1;
		for(int j = 0; j < a.size(); j++) {
			if(pow_mod(i, (x - 1) / a[j], x) == 1) {
				bk = 0; break;
			}
		} if(bk) {o = i; break;}
	}
	return o;
}

int BSGS(int a, int b, int p) {
	cnt = 0;
	LL t = sqrt(p) + 1, u = 1;
	for(int i = 0; i < t; i++) {
		LL x = ((LL)b * u) % p;
		num[++cnt] = x; id[cnt] = i;
		int oo = x % mod;
		if(!head[oo]) head[oo] = cnt;
		else {
			int y = head[oo];
			while(next[y]) y = next[y];
			next[y] = cnt;
		}
		(u *= a) %= p;
	}
	a = pow_mod(a, t, p);
	if(a == 0) {
		if(b == 0) return 1;
		return -1;
	} u = 1;
	for(int i = 0; i <= t; i++) {
		LL x = u;
		int z = x % mod;
		z = head[z];
		while(num[z] != x && z) z = next[z];
		if(num[z] == x) {
			LL j = id[z];
			if(i * t - j >= 0) return i * t - j;
		} (u *= a) %= p;
	} return -1;
}

LL exgcd(LL a, LL b, LL &x, LL &y) {
	if(b == 0) {
		x = 1; y = 0;
		return a;
	} else {
		LL tx, ty;
		LL d = exgcd(b, a % b, tx, ty);
		x = ty; y = tx - ty * (a / b);
		return d;
	}
}

int main() {
	int tt; scanf("%d", &tt);
	while(tt--) {
		LL p, a, b, x, y; scanf("%lld%lld%lld", &p, &a, &b);
		LL root = Find(p);
		memset(head, 0, sizeof(head));
		memset(next, 0, sizeof(next));
		memset(num, 0, sizeof(num));
		memset(id, 0, sizeof(id));
		LL c = BSGS(root, b, p);
		if(c == -1) {printf("No Solution\n"); continue;}
		b = p - 1;
		LL d = exgcd(a, b, x, y);
		if(c % d != 0) {printf("No Solution\n"); continue;}
		(x *= c / d) %= b;
		int len = 0;
		for(int i = 1; i <= d; i++) {
			(x += b / d) %= b; (x += b) %= b;
			o[++len] = pow_mod(root, x, p);
		} sort(o + 1, o + len + 1);
		for(int i = 1; i < len; i++) printf("%d ", o[i]);
		printf("%d\n", o[len]);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/xgc_woker/article/details/85638510