P3306 [SDOI2013] 随机数生成器
知识点: BSGS
原题面
题意简述
\(T\) 组数据,每组给定参数 \(p,a,b,x_1,t\)。
对于数列 \(x\),有 \(x_{i+1} \equiv a \times x_i + b \pmod p\)。
求最小的 \(i\),使 \(t = x_{i}\)。
\(1\le T\le 50, 0\le a,b,x_1,t <p, 2\le p\le 10^9\)。
保证 \(p\) 为质数。
分析题意
以下分析均在 \(\pmod p\) 下展开:
观察给定的递推式:
\[\begin{aligned}
x_2 \equiv& ax_1 + b\\
x_3 \equiv& a(a x_1 + b) +b=a^2x_1 +ab + b\\
x_4 \equiv& a^3x_1 +a^2b + ab + b
\end{aligned}\]
可知其通项公式:
\[x_i \equiv a^{i-1}x_1 +b\sum_{k=0}^{i-2}a_k
\]
发现后面一项为等比数列,套上求和公式略做处理:
\[\begin{aligned}
x_i \equiv& a^{i-1}x_1 +b\sum_{k=0}^{i-2}a_k\\
x_i \equiv& a^{i-1}x_1 +\dfrac{1-a^{i-1}}{1-a}b\\
(a-1)x_i \equiv& (a-1)a^{i-1}x_1 +(a^{i-1}+1)b\\
ax^{i}-x_i+b \equiv& (ax_1-x_1+b) a^{i-1}\\
a^{i-1} \equiv& \dfrac{ax^{i}-x_i+b}{ax_1-x_1+b}
\end{aligned}\]
将 \(t\) 代入,有:
\[a^{i-1} \equiv \dfrac{at-t+b}{ax_1-x_1+b}
\]
化出了一个长得就很 BSGS 的指数方程。
直接套 BSGS 即可,注意最后输出时答案+1。
细节
本题重点考察对象。
以下特判按照顺序展开。
- \(x_1=t\),直接输出 \(1\)。
- \(a=1\),\(x\) 变成了一个等差数列,有 \(x_i \equiv x_1+(i-1)b\)。
若 \(b=0\),则无解。
否则 代入 \(t\) 略做处理,有 \(i-1\equiv \dfrac{t-x_1}{b}\)。
费马小定理求出右侧,答案即右侧 + 1。 - \(a=0\),\(x\) 从第二项起变为常数列,有 \(x_i\equiv b (i>1)\)。
判断 \(b=t\) 是否成立,若成立答案为 \(2\),否则无解。
代码实现
//知识点:BSGS
/*
By:Luckyblock
*/
#include <map>
#include <cmath>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <algorithm>
#define ll long long
//=============================================================
ll p, a, b, x, t, T;
std :: map <ll, ll> mp;
//=============================================================
inline int read() {
int f = 1, w = 0; char ch = getchar();
for (; !isdigit(ch); ch = getchar()) if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void GetMax(int &fir, int sec) {
if (sec > fir) fir = sec;
}
void GetMin(int &fir, int sec) {
if (sec < fir) fir = sec;
}
ll QuickPow(ll x_, ll y_, ll mod_) {
ll ret = 1;
while (y_) {
if (y_ & 1) ret = 1ll * ret * x_ % mod_;
y_ >>= 1, x_ = 1ll * x_ * x_ % mod_;
}
return ret;
}
void Prepare() {
mp.clear();
b = ((t * a + b - t) % p + p) % p * QuickPow(((a * x + b - x) % p + p) % p, p - 2, p) % p;
}
void BabyStep() {
T = ceil(sqrt(double(p))) + 1;
ll sum = b;
for (ll r = 0; r < T; ++ r) {
mp[sum] = r;
sum = 1ll * sum * a % p;
}
}
ll GiantStep() {
if (b == 1) return 0;
ll at = QuickPow(a, T, p), sum = at;
if (! at) return (! b) ? 1 : - 1;
for (ll q = 1; q <= T; ++ q) {
if (mp.count(sum)) return q * T - mp[sum];
sum = (1ll * sum * at) % p;
}
return - 1;
}
//=============================================================
int main() {
int TestdataNum = read();
while (TestdataNum --) {
p = read(), a = read(), b = read(), x = read(), t = read();
if (x == t) {
printf("1\n");
continue ;
}
if (a == 1) {
if (! b) {
printf("-1\n");
} else {
t = ((t - x) % p + p) % p;
printf("%lld\n", t * QuickPow(b, p - 2, p) % p + 1);
}
continue ;
}
if (a == 0) {
printf("%d\n", b == t ? 2 : - 1);
continue ;
}
Prepare();
BabyStep();
ll ans = GiantStep();
printf("%d\n", ans >= 0 ? ans + 1 : - 1);
}
return 0;
}
作者@Luckyblock,转载请声明出处。