【洛谷P3306】随机数生成器
题目
题目链接:https://www.luogu.com.cn/problem/P3306
小W喜欢读书,尤其喜欢读《约翰克里斯朵夫》。最近小W准备读一本新书,这本书一共有\(P\)页,页码范围为\(0 \cdots P-1\)。
小W很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用NOI2012上学习的线性同余法生成一个序列,来决定每天具体读哪一页。
我们用Xi来表示通过这种方法生成出来的第\(i\)个数,也即小\(W\)第\(i\)天会读哪一页。这个方法需要设置\(3\)个参数\(a,b,X1\),满足\(0\leq a,b,X1\leq p-1\),且\(a,b,X1\)都是整数。按照下面的公式生成出来一系列的整数:\(X_{i+1} \equiv aX_i+b \pmod p\)其中\(mod\)表示取余操作。
但是这种方法可能导致某两天读的页码一样。
小W要读这本书的第\(t\)页,所以他想知道最早在哪一天能读到第t页,或者指出他永远不会读到第\(t\)页。
思路
题目意思就是给你一个递推式\(X_i=aX_{i-1}+b\)和\(X_1\),让你求一个最小的\(i\)使得\(X_i\equiv t \pmod p\)。
大力推柿子,容易得到
\[X_i=a^{i-1}X_1+a^{i-2}b+a^{i-3}b+...+b
\]
我们发现所有含有\(b\)的项是一个等比数列,所以可以用等比数列求和公式化简。
\[X_i=a^{i-1}X_1+\frac{a^{i-1}b-b}{a-1}
\]
也就是要求
\[t\equiv a^{i-1}X_1+\frac{a^{i-1}b-b}{a-1} \pmod p
\]
在这个柿子中,只有\(a^{i-1}\)是未知的。所以考虑化简出\(a^{i-1}\)。
\[t+\frac{b}{a-1}\equiv a^{i-1}X_1+\frac{a^{i-1}b}{a-1} \pmod p
\]
\[t+\frac{b}{a-1}\equiv a^{i-1}(X_1+\frac{b}{a-1}) \pmod p
\]
所以
\[a^{i-1}\equiv \frac{t+\frac{b}{a-1}}{X_1+\frac{b}{a-1}}\pmod p
\]
\[a^{i-1}\equiv \frac{ta-t+b}{X_1a-X_1+b}\pmod p
\]
用\(BSGS\)求出\(i-1\)即可。
需要特判以下几点:
- 当\(X_1=t\)时,答案就是1。
- 当\(a=0\)时,第一天已经在\((1)\)中特判了,从第二天起,页码都是\(b\)。所以如果\(b=t\)答案即为2,否则无解。
- 当\(a=1\)时
- 如果\(b=0\),那么每天页码都是\(X_1\),所以若\(X_1≠t\)则无解
- 如果\(b>0\),那么有\(X_1+xb\equiv t \pmod p\),即\(x\equiv \frac{t-X_1}{b}\pmod p\),用费马小定理即可求出\(x\)。
代码
#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll p,a,b,x1,t;
int T;
map<int,int> hash;
ll power(ll x,ll k,ll MOD)
{
ll ans=1;
x%=MOD;
for (;k;k>>=1,x=x*x%MOD)
if (k&1) ans=ans*x%MOD;
return ans;
}
ll BSGS()
{
hash.clear();
t=ceil(sqrt(p));
for (int i=0;i<=t;i++)
hash[b*power(a,i,p)%p]=i;
a=power(a,t,p);
for (int i=1;i<=t;i++)
{
ll val=power(a,i,p);
if (hash[val]) return ((i*t-hash[val])%p+p)%p;
}
return -2;
}
int main()
{
scanf("%d",&T);
while (T--)
{
scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
if (x1==t) printf("1\n");
else if (!a)
{
if (b==t) printf("2\n");
else printf("-1\n");
}
else if (a==1)
{
if (!b) printf("-1\n");
else printf("%lld\n",((t-x1)%p+p)%p*power(b,p-2,p)%p+1);
}
else
{
b=(t*a-t+b)%p*power(x1*a-x1+b,p-2,p)%p;
printf("%lld\n",BSGS()+1);
}
}
return 0;
}