题解——随机数生成器
[SDOI2013] 随机数生成器
题目背景
小 W 喜欢读书,尤其喜欢读《约翰克里斯朵夫》。
题目描述
最近小 W 准备读一本新书,这本书一共有
小 W 很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用 NOI2012 上学习的线性同余法生成一个序列,来决定每天具体读哪一页。
我们用
其中
但是这种方法可能导致某两天读的页码一样。
小 W 要读这本书的第
输入格式
本题单测试点内有多组测试数据。
第一行是一个整数
接下来
输出格式
对于每组数据,输出一行一个整数表示他最早读到第
样例 #1
样例输入 #1
3
7 1 1 3 3
7 2 2 2 0
7 2 2 2 1
样例输出 #1
1
3
-1
提示
数据规模与约定
对于全部的测试点,保证:
。 , 。 为质数。
题解
首先大致拆开一下式子
越拆越觉得涉及到高次同余式,考虑
考虑转化为等比数列,设
变形,得到
有:
进一步的
所以说,我们解出这个同余式的解即可
不过有几个特殊情况需要判断,就是
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define int long long
map<int, int>h;
int t, a, b, x, p, ans;
int power(int a, int b, int p) {
int ans = 1;
while (b) {
if (b & 1)ans = ans * a % p;
a = a * a % p;
b >>= 1;
}
return ans % p;
}
int BSGS(int x) {
h.clear();
int a_inv = power(a - 1, p - 2, p);
int x_a_inv = power((x + b * a_inv % p) % p, p - 2, p);
int s = (t + b * a_inv) % p * x_a_inv % p;
int pq = sqrt(p) + 1;
for (int i = 0; i < pq; i++) {
h[s * power(a, i, p) % p] = i;
}
a = power(a, pq, p);
if (!a) {
return s == 0 ? 1 : -1;
}
for (int i = 1; i <= pq; i++) {
int sq = power(a, i, p);
if (h.find(sq) != h.end() && pq * i - h[sq] > 0) {
return pq * i - h[sq] + 1;
}
}
return -1;
}
signed main() {
int T;
scanf("%lld", &T);
while (T--) {
scanf("%lld%lld%lld%lld%lld", &p, &a, &b, &x, &t);
ans = 0;
if (x == t) {
puts("1");
}
else if (a == 0) {
if (t == b)puts("2");
else puts("-1");
}
else if (a == 1 && b == 0) {
puts("-1");
}
else if (a == 1) {
int inv = power(b, p - 2, p);
ans = ((t - x) % p + p) % p * inv % p;
printf("%lld\n", ans + 1);
}
else {
printf("%lld\n", BSGS(x));
}
}
}
如何想到这个做法?由递归式会使得式子变成高次式,就启发BSGS,BSGS又能启发我们转化等比数列
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!