• 【JZOJ3211】【SDOI2013】随机数生成器


    ╰( ̄▽ ̄)╭

    小 W喜欢读 书,尤其喜欢读 书,尤其喜欢读《约翰克里斯 朵夫》。 最近小 W准备读一本新书,这本一共有 p页, 页码范围为 0..p -1。
    小 W很忙,所以每天只能读一页书 。为了使事情有趣一些 ,他打算使用 NOI2012上学习的线性同余法生成 一个序列 ,来决定每天具体读哪一页 。
    我们用 Xi来表示通过这种方法生成出来第 i个数 ,也即小 W第 i天会读 哪一页 。这个方法 需要设置 3个参数 a,b,X1,满足 0≤a,b,X1≤p-1,且 a, b,X1都是整数 。按照下面的公式 按照下面的公式生成出来一系列的 整数。
    Xi+1=(aXi+b)modp
    其中 mod p 表示前面的数除以 p的余数。
    可以发现,这个序列中下一个数总是由上一个数生成的 ,而且每一项都在 0..p -1这个范围内 ,是一个合法的页码。 同时需要注意 ,这种方法有可能导致某两天读的页码完全一样 。
    小 W非常急切 地想去读这本书的第t页。所以他想知道, 对于一组给定的 a, b,X1,如果使用线性同余法来生成每一天读的页码, 最早读到第t页是在哪一天,或者指出他永远不会读到第t页。
    p<=109

    (⊙ ▽ ⊙)

    容易求出x的通项公式,
    c=ba1

    xn=an1(x1+c)c


    特殊情况的处理:
    在此之前我们必须保证a!=1
    所以我们对于a=1的情况利用扩展欧几里得求解。
    同时我们也得保证a!=0,因为当a=0并且n=1时,00是无意义的。
    于是对于a=0的情况直接特判求解。


    此时,题目要求的是:xnt(mod p),等价于:an1(x1+c)ct(mod p)
    移项可得:an1t+cx1+c(mod p)


    特殊情况的处理:
    在此之前,我们还要保证x1b不同时为0,否则会使得x1+c这个分母为0
    所以对于x1b同时为0的情况特判求解。


    ans=n1 , S=t+cx1+c,最终题目转化为求

    aansS(mod p)

    的最小正整数解。(关于ans

    于是就能套大步小步算法(BSGS algorithm)了。

    ( ̄~ ̄)

    #include<iostream>
    #include<algorithm>
    #include<stdio.h>
    #include<string.h>
    #include<math.h>
    #define ll long long
    using namespace std;
    const char* fin="jzoj3211.in";
    const char* fout="jzoj3211.out";
    const ll inf=0x7fffffff;
    const ll maxh=1000007;
    ll t,i,j,k,A,B,X1,n,mo;
    ll h[maxh],minx[maxh];
    bool noans;
    ll hash(ll v){
        ll k=v%maxh;
        while (h[k] && h[k]!=v) k=(k+1)%maxh;
        return k;
    }
    ll exgcd(ll a,ll b,ll &x,ll &y){
        if (b==0){
            x=1;
            y=0;
            return a;
        }
        ll r=exgcd(b,a%b,x,y);
        ll t=x;
        x=y;
        y=t-a/b*y;
        return r;
    }
    ll qpower(ll a,ll b){
        ll c=1;
        while (b){
            if (b&1) c=c*a%mo;
            a=a*a%mo;
            b>>=1;
        }
        return c;
    }
    int main(){
        freopen(fin,"r",stdin);
        freopen(fout,"w",stdout);
        scanf("%lld",&t);
        while (t--){
            scanf("%lld%lld%lld%lld%lld",&mo,&A,&B,&X1,&n);
            if (A==0){
                if (X1==n) printf("1
    ");
                else if (B==n) printf("2
    ");
                else printf("-1
    ");
            }else if (A==1){
                ll x,y;
                k=exgcd(mo,B,x,y);
                if ((n-X1)%k) printf("-1
    ");
                else{
                    x*=(n-X1)/k;
                    y*=(n-X1)/k;
                    y=(y%(mo/k)+(mo/k))%(mo/k);
                    printf("%lld
    ",y+1);
                }
            }else if (B==0 && X1==0){
                if (X1==n) printf("1
    ");
                else printf("-1
    ");
            }else{
                ll ks=(ll)sqrt(mo),tmp=qpower(A,ks),tmd=qpower(tmp,mo-2);
                memset(h,0,sizeof(h));
                memset(minx,0,sizeof(minx));
                j=1;
                for (i=0;i<ks;i++){
                    k=hash(j);
                    h[k]=j;
                    if (!minx[k] || minx[k]>i) minx[k]=i;
                    j=j*A%mo;
                }
                ll C=B*qpower(A-1,mo-2)%mo;
                j=(n+C)*qpower(X1+C,mo-2)%mo;
                noans=true;
                for (i=0;i<=ks;i++){
                    k=hash(j);
                    if (h[k]){
                        ll ans=minx[k]+i*ks+1;
                        printf("%lld
    ",ans);
                        noans=false;
                        break;
                    }
                    j=j*tmd%mo;
                }
                if (noans) printf("-1
    ");
            }
        }
        return 0;
    }

    (⊙v⊙)

    对于一个有递推式的问题,可以考虑先求出通项公式,在对其因式分解。

  • 相关阅读:
    漫话性能:USE方法
    MIPI 屏参调试
    Linux下访问匿名页发生的神奇“化学反应”
    USB 2.0 suspend resume
    谈谈Linux内核驱动的coding style
    Apollo ROS原理(一)
    BMS(电池管理系统)第五课 ——核心!!!SOH算法开发
    蓝牙核心技术概述(一)蓝牙概述
    BMS(电池管理系统)第三课 ——BMS功能清单和采样要求
    登录密码加密vue版(转载)
  • 原文地址:https://www.cnblogs.com/hiweibolu/p/6714795.html
Copyright © 2020-2023  润新知