51nod1038 X^A Mod P 原根+BSGS

2 篇文章 0 订阅
1 篇文章 0 订阅

Description
X A m o d P = B X^A mod P = B XAmodP=B,其中 P P P为质数。给出 P P P A A A B B B,求 &lt; P &lt; P <P的所有 X X X
例如: P = 11 , A = 3 , B = 5 P = 11,A = 3,B = 5 P=11A=3B=5
3 3 M o d 11 = 5 3^3 Mod 11 = 5 33Mod11=5
所有数据中,解的数量不超过 S q r t ( P ) Sqrt(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 g P P P的原根那么与 P P P互质的数,都可以由 g g g为底数的次幂表示出来。
一个数有原根,当且仅当这个数为: P = 1 , 2 , 4 , p a , 2 p a P=1,2,4,p^a,2p^a P=1,2,4,pa,2pa
一个数 P P P,它的原根数量为 p h i ( p h i ( P ) ) phi(phi(P)) phi(phi(P))
最小的原根一般比较小,于是我们考虑暴力枚举。
判断一个数 g g g是否是 P P P的原根:
1. 1. 1.暴力枚举。
2. 2. 2. ( P − 1 ) (P-1) (P1)的约数中有一个质数满足 g ( P − 1 ) / p i = = 1 ( m o d P ) g^{(P-1)/pi}==1(mod P) g(P1)/pi==1(modP),那么就不是原根。

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


#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值