BZOJ3122 随机数生成器——BSGS
题意
给定 $p,\ a,\ b, \ x_1$,现有一数列
$$x_{i+1} \equiv (ax_i + b) \ mod \ p$$
求最小的 $i$ 满足 $x_i = t$
分析
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; //ax + by = d,且|x|+|y|最小,其中d=gcd(a,b) //即使a, b在int范围内,x和y也有可能超过int范围 void exgcd(ll a, ll b, ll &d, ll &x, ll &y) { if (!b){ d = a; x = 1; y = 0;} else{ exgcd(b, a % b, d, y, x); y -= x * (a / b);} } //计算模n下a的逆。如果不存在逆,返回-1 //ax=1(mod n) ll inv(ll a, ll n) { ll d, x, y; exgcd(a, n, d, x, y); return d == 1 ? (x + n) % n : -1; } inline ll bsgs(ll a, ll b, ll p) { a %= p; b %= p; std::map<ll, ll> map; ll m = ceil(sqrt(p)), t = 1; for (int i = 0; i < m; i++) { if (!map.count(t)) map[t] = i; t = t * a % p; } ll k = inv(t, p), w = b; for (int i = 0; i < m; i++) { if (map.count(w)) return i * m + map[w]; w = w * k % p; } return -1; } inline ll solve(ll p, ll a, ll b, ll x1, ll t) { if (t == x1) return 1; else if (a == 0) return b == t ? 2 : -1; else if (a == 1) { if (!b) return -1; return ((((t - x1) % p + p) % p) * inv(b, p) % p) + 1; } else { ll q = inv(1 - a + p, p); ll d = (((t - b * q) % p + p) % p) * inv(((x1 - b * q) % p + p) % p, p); ll ans = bsgs(a, d, p); if (ans == -1) return -1; else return ans + 1; } } int main() { int T; scanf("%d", &T); while (T--) { int p, a, b, x1, t; scanf("%d %d %d %d %d", &p, &a, &b, &x1, &t); printf("%lld\n", solve(p, a, b, x1, t)); } }
发现BZOJ还能下测试数据:https://darkbzoj.tk/data/
个性签名:时间会解决一切