SGU 261 Discrete Roots (经典K次剩余)

47 篇文章 0 订阅
20 篇文章 0 订阅

首先求p的原根g,  g满足g^(phi(n)/pi) mod n 均不等于1,令g^y=x,g^t=a 得到 g^yk=g^t(modp) (a=0特判)  此式 可转化为 k*y=t(mod(phi(p))); 即 k*y=t(mod(p-1)),接下来就是求g^t=a(mod(p)) ,用babystep 求离散对数的方法求出t ,然后解模线性方程 k*y=t(mod(p-1)), 得到所有的y, y的解的个数为gcd(k,p-1),然后我们就可以求出所有的x,排序输出就行了

#include<cstdio>
#include<cstring>
#include<queue>
#include<vector>
#include<iostream>
#include<string>
#include<sstream>
#include<cctype>
#include<set>
#include<stack>
#include<functional>
#include<memory>
#include<deque>
#include<list>
#include<cmath>
#include<fstream>
#include<cstdlib>
#include<climits>
#include<iomanip>
#include<cstring>
#include<memory>
#include<bitset>
#include<algorithm>
using namespace std;
#define  lson l, m, rt<<1
#define  rson m+1,r,rt<<1|1
typedef long long LL;
typedef vector<unsigned int> VI;
typedef vector<VI> VVI;
typedef vector<VVI> VVVI;
const int maxn = 40000;
const int mod = 1000000007;
const int hash_size = 175447;
const double pi = acos(-1.0);
const double eps = 1e-10;
bitset<maxn + 10> a;
int p[maxn], size;
void init() {
	int i, j;
	for (i = 2; i <= 200; ++i)
		if (!a[i])
			for (j = i * i; j <= maxn; a[j] = 1, j += i)
				;
	for (i = 2; i <= 40000; ++i)
		if (!a[i])
			p[size++] = i;
}
int f[maxn], c[maxn], cnt;
void spilt(int n) {
	cnt = 0;
	int i, t = n;
	for (i = 0; i < size && p[i] * p[i] <= t; ++i) {
		if (t % p[i] == 0) {
			f[cnt] = p[i];
			while (t % p[i] == 0) {
				c[cnt]++;
				t /= p[i];
			}
			cnt++;
		}
	}
	if (t > 1) {
		f[cnt] = t;
		c[cnt]++;
		cnt++;
	}
}
int factor[maxn], tsize;
void dfs(int t, int dep) {
	if (dep == cnt) {
		factor[tsize++] = t;
		return;
	}
	for (int i = 0; i <= c[dep]; t *= f[dep], ++i) {
		dfs(t, dep + 1);
	}
}
int POW(LL a, LL b, LL mod) {
	LL res = 1;
	while (b) {
		if (b & 1)
			res = res * a % mod;
		a = a * a % mod;
		b >>= 1;
	}
	return (int) res;
}
int PrimitiveRoot(int n) {
	if (n == 2)
		return 1;
	int i, j;
	bool flag = false;
	for (i = 2; i < n; ++i) {
		flag = true;
		for (j = 0; j < tsize; ++j) {
			if (POW(i, factor[j], n) == 1) {
				flag = false;
				break;
			}
		}
		if (flag)
			return i;
	}
	return -1;
}
struct node {
	LL key;
	int val, next;
	node() {
	}
	node(LL key, int val, int next) :
			key(key), val(val), next(next) {
	}
} edge[hash_size + 10];
struct HashMap {
	int i, E;
	int head[hash_size + 10];
	void init() {
		E = 0;
		memset(head, -1, sizeof(head));
	}
	bool insert(LL key, int val) {
		int u = key % hash_size;
		for (i = head[u]; ~i; i = edge[i].next) {
			if (edge[i].key == key)
				return false;
		}
		edge[E] = node(key, val, head[u]);
		head[u] = E++;
		return true;
	}
	int find(LL key) {
		int u = key % hash_size;
		for (i = head[u]; ~i; i = edge[i].next) {
			if (edge[i].key == key)
				return edge[i].val;

		}
		return -1;
	}
} Hash;
LL exgcd(LL a, LL b, LL &x, LL &y) {
	if (b == 0) {
		x = 1;
		y = 0;
		return a;
	}
	LL d = exgcd(b, a % b, x, y);
	LL t = x;
	x = y;
	y = t - (a / b) * y;
	return d;
}
LL go(LL A, LL B, LL C) {

	int i, m = (int) ceil(sqrt(C + 0.0));
	Hash.init();
	LL t = 1;
	Hash.insert(1, 0);
	for (i = 1; i <= m; ++i) {
		t = t * A % C;
		if (t == B)
			return i;
		Hash.insert(t, i);
	}
	LL P = 1, x, y;
	for (i = 1; i <= m; ++i) {
		P = P * t % C;
		exgcd(P, C, x, y);
		x *= B;
		x = (x % C + C) % C;
		y = Hash.find(x);
		if (y >= 0)
			return (int) (i * m + y);
	}
	return -1;
}
LL ans[maxn];
int Ccnt;
int main() {
	ios::sync_with_stdio(false);
	init();
	int i, p, k, a;
	scanf("%d%d%d", &p, &k, &a);
	if (!a) {
		puts("1");
		puts("0");
		return 0;
	}
	spilt(p - 1);
	dfs(1, 0);
	sort(factor, factor + tsize);
	--tsize;
	LL g = PrimitiveRoot(p);
	LL t = go(g, a, p);
	LL x, y, b = p - 1, M;
	LL d = exgcd(k, b, x, y);
	if (t % d) {
		puts("0");
		return 0;
	}
	M = b / d;
	x *= t / d;
	x = (x % M + M) % M;
	for (i = 0; i < d; x = x + M, ++i) {
		ans[Ccnt++] = POW(g, x, p);
	}
	sort(ans, ans + Ccnt);
	printf("%d\n", Ccnt);
	for (i = 0; i < Ccnt; ++i) {
		printf("%I64d\n", ans[i]);
	}
	return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值