BZOJ 3122: [Sdoi2013]随机数生成器

\(X_{i+1}\equiv aX_i+b \pmod p\)
\(X_{i+1}+z \equiv a(X_i+z) \pmod p\)
其中 \(z \equiv b(a-1)^{-1} \pmod p\)
即求 \((X_1+z)a^{n-1} - z \equiv t \pmod p\) 的最小自然数解 \(n\)
特判几种情况
一,第一天就看的那一页
二、\(a=0\) 之后每天都看同一页 \(b\)
三、\(a=1\),当 \(b\)\(0\) 时,也是每一天都看同一页,\(b\) 不为 \(0\) 时为等差数列,求同余方程的解

#include <bits/stdc++.h>

const int INF = 0x3f3f3f3f;

int qp(int a, int b, int p) {
	a %= p;
	if (!a) return 0;
	int res = 1;
	while (b > 0) {
		if (b & 1) res = 1LL * res * a % p;
		a = 1LL * a * a % p;
		b >>= 1;
	}
	return res % p;
}

int gcd(int a, int b) {
	while (b) {
		a %= b;
		std::swap(a, b);
	}
	return a;
}

struct Ha {
	static const int mod = 1e6 + 7;
	int head[mod + 5], cnt;
	struct E {
		int x, ans, ne;
	} e[mod << 1];
	void clear() {
		cnt = 1;
		memset(head, 0, sizeof(head));
	}
	Ha() { clear(); }
	void insert(int x, int v) {
		int u = x % mod;
		e[++cnt].x = x; e[cnt].ans = v; e[cnt].ne = head[u]; head[u] = cnt;
	}
	int operator[](const int &k) const {
		int u = k % mod;
		for (int i = head[u]; i; i = e[i].ne)
			if (e[i].x == k) return e[i].ans;
		return -1;
	}
} H;

int BSGS(int a, int b, int mod) {
	if (mod == 1) return 0;
	if (a >= mod) a %= mod;
	if (b >= mod) b %= mod;
	if (a == 0) return b == 0 ? 1 : -1;
	if (b == 1) return 0;
	int m = ceil(sqrt(mod + 0.5));
	H.clear();
	for (int B = 0; B < m; B++) {
		H.insert(b, B);
		b = 1LL * b * a % mod;
	}
	int base = qp(a, m, mod), cur = base;
	for (int A = 1; A <= m + 1; A++) {
		int B = H[cur];
		if (~B) return A * m - B;
		cur = 1LL * cur * base % mod;
	}
	return -1;
}

int solve() {
	int p, a, b, x1, t;
	scanf("%d%d%d%d%d", &p, &a, &b, &x1, &t);
	if (x1 == t) return 1;
	if (a == 0) {
		if (b == t) return 2;
		return -1;
	}
	if (a == 1) {
		if (b == 0) return -1;
		t -= x1;
		if (t < 0) t += p;
		t = 1LL * t * qp(b, p - 2, p) % p;
		return t + 1;
	}
	int z = 1LL * b * qp(a - 1, p - 2, p) % p;
	x1 += z;
	if (x1 >= p) x1 -= p;
	t += z;
	if (t >= p) t -= p;
	b = 1LL * t * qp(x1, p - 2, p) % p;
	int ans = BSGS(a, b, p);
	if (ans == -1) return -1;
	return ans + 1;
}

int main() {
	//freopen("ans.out", "w", stdout);
	int T;
	scanf("%d", &T);
	while (T--) 
		printf("%d\n", solve());
	return 0;
}
posted @ 2020-02-12 22:54  Mrzdtz220  阅读(151)  评论(0)    收藏  举报