【洛谷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\)即可。

需要特判以下几点:

  1. \(X_1=t\)时,答案就是1。
  2. \(a=0\)时,第一天已经在\((1)\)中特判了,从第二天起,页码都是\(b\)。所以如果\(b=t\)答案即为2,否则无解。
  3. \(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;
}

猜你喜欢

转载自www.cnblogs.com/stoorz/p/12236384.html
今日推荐