[SDOI2013]随机数生成器(BSGS)

时间:2019-10-18
本文章向大家介绍[SDOI2013]随机数生成器(BSGS),主要包括[SDOI2013]随机数生成器(BSGS)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

这题妙啊,我们做这道题遇到的首先一个门槛就是推式子:
\[ X_{i+1}=aX_{i}+b \]
我们考虑两边同时加上\(\frac{b}{a-1}\),这样我们就构造出了一个等比数列:
\[ X_{i+1}+\frac{b}{a-1}=a(X_i+\frac{b}{a-1})(mod\:p) \]
然后就是简单的等比数列求第\(n\)项:
\[ X_{n}+\frac{b}{a-1}=a^{n-1}(X_1+\frac{b}{a-1})(mod\:p) \]
上式只有\(n\)是未知的,我们移项可得:
\[ a^{n-1}\equiv(X_n+b*inv(a-1))*inv(X_1+b*inv(a-1))(mod\:p) \]
我们求\(n\)就直接用bsgs就好了,注意明显的特殊数据就直接特判输出答案,看代码

#pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,C;
ll powmod(ll x,ll y,ll mod)
{
    ll sum=1;
    while(y)
    {
        if(y&1)
        {
            sum=sum*x%mod;
        }
        x=x*x%mod;
        y>>=1;
    }
    return sum;
}
map<ll,ll> mp;
void bsgs(ll x,ll y,ll mod)
{
    ll i,j;
    if(x%mod==0)
    {
        printf("-1\n");
        return;
    }
    mp.clear();
    ll m=sqrt(mod)+1,t,tt;
    for(i=0,t=y;i<m;++i,t=t*x%mod) mp[t]=i;
    for(i=1,tt=powmod(x,m,mod),t=tt;i<=m;i++,t=t*tt%mod)
    {
        j=mp.find(t)==mp.end()?-1:mp[t];
        if(j>=0&&i*m-j>=0)
        {
            printf("%lld\n",i*m-j+1);
            return;
        }
    }
    printf("-1\n");
}
int main()
{
    ll i,j,p,a,b,X1,t;
    scanf("%lld",&T);
    while(T--)
    {
        scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&X1,&t);
        if(X1==t){puts("1");continue;}
        if(a==0){puts(t==b?"2":"-1");continue;}
        if(a==1&&b==0){puts("-1");continue;}
        if(a==1){
            ll ny=powmod(b,p-2,p);
            ll ans=((((t-X1)%p+p)%p)*ny%p)%p;
            printf("%lld\n",ans+1);continue;
        }
        ll u=b%p*powmod(a-1,p-2,p);
        ll cc=(X1+u)%p;
        C=(t+u)%p*powmod(cc,p-2,p)%p;
        bsgs(a,C%p,p);
    }
    return 0;
} 

原文地址:https://www.cnblogs.com/yzxx/p/11700388.html