多次剩余原根法

多次剩余:
x a = b ( m o d   p ) x^{a}=b(mod~p) xa=b(mod p),p是质数的所有解。

找到p的原根g,设 g B = b g^{B}=b gB=b,这个用bsgs求。

x a = b ( m o d   p ) x^a=b(mod~p) xa=b(mod p)
等价于 g a ∗ x = g B ( m o d   p ) g^{a*x}=g^{B}(mod~p) gax=gB(mod p)
a ∗ x = B ( m o d   ( p − 1 ) ) a*x=B(mod~(p-1)) ax=B(mod (p1))

那么用exgcd解即可。

例题:
http://www.51nod.com/Challenge/AcceptedRank.html#!#problemId=1038

卡常:写bsgs时可以利用边集数组,会比哈希表快一些。

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define pp printf
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

int T;
ll a, b, mo, g;
ll u[20], v[20], u0;

ll ksm(ll x, ll y) {
	ll s = 1;
	for(; y; y /= 2, x = x * x % mo)
		if(y & 1) s = s * x % mo;
	return s;
}

void fen(ll x) {
	u0 = 0;
	for(int i = 2; i * i <= x; i ++) if(x % i == 0) {
		u[++ u0] = i; v[u0] = 0;
		while(x % i == 0) x /= i, v[u0] ++;
	}
	if(x > 1) u[++ u0] = x, v[u0] = 1;
}

int pdg(int x) {
	fo(i, 1, u0) if(ksm(x, (mo - 1) / u[i]) == 1) return 0;
	return 1;
}

void fg() {
	fo(i, 2, mo) if(pdg(i))
		{ g = i; return;}
}

const int M = 1e5 + 7;
int fi[M], to[M], nt[M], V[M], tot;

void link(int x, int y, int z) {
	nt[++ tot] = fi[x], to[tot] = y, V[tot] = z, fi[x] = tot;
}


int bsgs(int a, int b) {
	tot = 0; memset(fi, 0, sizeof fi);
	int m = ceil(sqrt(mo));
	ll x = b;
	fo(i, 1, m) {
		x = x * a % mo;
		link(x % M, x, i);
	}
	x = 1; ll am = ksm(a, m);
	fo(i, 1, m) {
		x = x * am % mo;
		for(int j = fi[x % M]; j; j = nt[j])
			if(to[j] == x) return i * m - V[j];
	}
	return -1;
}

int gcd(int x, int y) {
	return !y ? x : gcd(y, x % y);
}

void exgcd(int a, int b, int &x, int &y) {
	if(!b) {x = a; y = 0; return;}
	exgcd(b, a % b, y, x); y -= (a / b) * x;
}

int ans[100000];

void gg(int a, int b, int c) {
	int d = gcd(a, b);
	if(c % d) return;
	a /= d; b /= d; c /= d;
	int x, y; exgcd(a, b, x, y);
	x = (ll) (x % b + b) * c % b;
	fo(i, 1, d) ans[++ ans[0]] = (i - 1) * b + x;
}

int main() {
	for(scanf("%d", &T); T; T --) {
		scanf("%lld %lld %lld", &mo, &a, &b);
		if(mo == 2) {
			if(b == 0) pp("1\n0\n"); else
			pp("1\n1\n");
			continue;
		}
		fen(mo - 1); fg();
		int B = bsgs(g, b);
		ans[0] = 0;
		gg(a, mo - 1, B);
		fo(i, 1, ans[0]) ans[i] = ksm(g, ans[i]);
		sort(ans + 1, ans + ans[0] + 1);
		ans[0] = unique(ans + 1, ans + ans[0] + 1) - (ans + 1);
		if(ans[0] == 0) {
			pp("No Solution\n");
		} else {
			fo(i, 1, ans[0]) pp("%d ", ans[i]);
			pp("\n");
		}
	}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值