P3306 [SDOI2013] 随机数生成器
题目描述:
最近小 W 准备读一本新书,这本书一共有 \(p\) 页,页码范围为 \(0 \sim p-1\)。
小 W 很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用 NOI2012 上学习的线性同余法生成一个序列,来决定每天具体读哪一页。
我们用 \(x_i\) 来表示通过这种方法生成出来的第 \(i\) 个数,也即小 W 第 \(i\) 天会读哪一页。这个方法需要设置 \(3\) 个参数 \(a,b,x_1\),满足 \(0\leq a,b,x_1\lt p\),且 \(a,b,x_1\) 都是整数。按照下面的公式生成出来一系列的整数:
$x_{i+1} \equiv a \times x_i+b \pmod p $
其中 \(\ mod\) 表示取余操作。
但是这种方法可能导致某两天读的页码一样。
小 W 要读这本书的第 \(t\) 页,所以他想知道最早在哪一天能读到第 \(t\) 页,或者指出他永远不会读到第 \(t\) 页。
数据范围:\(1\leq T\leq 50\), \(0 \leq a, b, x_1, t \lt p\), \(2 \leq p \leq 10^9\), \(p\) 为质数。
solution
我们尝试打一下表,找找规律:
\(x_2 = ax_1 + b\)
\(x_3 = a^2x_1 + ab + b\)
\(x_4 = a^3x_1 + a^2b + ab + b\)
\(x_5 = a^4x_1 + a^3b + a^2b + ab + b\)
\(x_6 = a^5x_1 + a^4b + a^3b + a^2b + ab + b\)
不难发现: \(x_n = a^{n-1}x_1 + \displaystyle\sum_{i=0}^{n-2} a^ib, (x \gt 1)\)
根据等比数列的求和公式则有: \(\displaystyle\sum_{i=0}^{n-2} a^ib = b{1-a^{n-1}\over 1-a}\) 。
带入可得:\(x_n = a^{n-1}x_1 + {b\over 1-a} (1-a^{n-1})\) 。
化简一下:
\(x_n = a^{n-1}x_1 + {b\over 1-a} (1-a^{n-1})\)
\(x_n = a^{n-1}x_1 - a^{n-1}{b\over 1-a} + {b\over 1-a}\)
设 \(B = {b\over 1-a}\), 则原式可以化为:
\(x_n = (x_1-B) a^{n-1} + B\)
\(\because x_n \equiv t\)
\(\therefore (x_1-B) a^{n-1} + B\equiv t\) 。
\(\therefore (x_1-B)a^{n-1} \equiv t-B \pmod p\)
\(\therefore a^{n-1} \equiv {t-B\over x_1-B} \pmod p\)
用 \(BSGS\) 算法求解即可。
几个需要特判的点 (被卡到吐):
- 当 \(x_1 = t\) 的时候,直接输出 \(1\)
- 当 \(a = 0\) 的时候,如果 \(t = b\) 输出 \(1\) , 反之输出 \(-1\)
- 当 \(a = 1\) 的时候, 如果 \(b = 0\) 且 \(x \neq t\) 输出 \(-1\), 否则输出 \((t-x) \over b\)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define int long long
int T,a,b,p,x,t;
inline int read()
{
int s = 0, w = 1; char ch = getchar();
while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
return s * w;
}
int ksm(int a,int b)
{
int res = 1;
for(; b; b >>= 1)
{
if(b & 1) res = res * a % p;
a = a * a % p;
}
return res;
}
int BSGS(int a,int b,int p)
{
map<int,int> hash;
int m = sqrt(p) + 1;
for(int i = 0; i <= m; i++)
{
int val = b * ksm(a,i) % p;
hash[val] = i;
}
a = ksm(a,m);
for(int i = 0; i <= m; i++)
{
int val = ksm(a,i);
int j = hash.find(val) == hash.end() ? -1 : hash[val];
if(j > 0 && i * m - j > 0) return i * m - j;
}
return -1;
}
signed main()
{
T = read();
while(T--)
{
p = read(); a = read(); b = read(); x = read(); t = read();
if(x == t){printf("%d\n",1); continue;}
if(a == 0)
{
if(t == x) printf("%d\n",1);
else if(t == b) printf("%d\n",2);
else printf("%d\n",-1);
continue;
}
if(a == 1)
{
if(b == 0 && x != t) printf("%d\n",-1);
else printf("%lld\n",(((t-x+p)%p)*ksm(b,p-2)%p)+1);
continue;
}
int tmp = (1 - a + p) % p;
int inv = ksm(tmp,p-2);
t = (t - (b * inv % p) + p) % p;
x = (x - (b * inv % p) + p) % p;
t = t * ksm(x,p-2) % p;
int ans = BSGS(a,t,p);
if(ans == -1) printf("%d\n",-1);
else printf("%lld\n",ans+1);
}
return 0;

浙公网安备 33010602011771号