zoukankan      html  css  js  c++  java
  • 【洛谷】P3306 [SDOI2013]---- 随机数生成器

    题目背景

    (W) 喜欢读书,尤其喜欢读《约翰克里斯朵夫》。

    题目描述

    最近小 (W) 准备读一本新书,这本书一共有 (p) 页,页码范围为 (0 sim p-1)

    (W) 很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用 (NOI2012) 上学习的线性同余法生成一个序列,来决定每天具体读哪一页。

    我们用 (x_i) 来表示通过这种方法生成出来的第 ii 个数,也即小 W 第 ii 天会读哪一页。这个方法需要设置 (3) 个参数 (a,b,x_1) ,满足 (0leq a,b,x_1lt p0),且 (a,b,x_1) 都是整数。按照下面的公式生成出来一系列的整数:

    (x_{i+1} equiv a imes x_i+b pmod p)

    其中 (mod) 表示取余操作。

    但是这种方法可能导致某两天读的页码一样。

    (W) 要读这本书的第 (t) 页,所以他想知道最早在哪一天能读到第 (t) 页,或者指出他永远不会读到第 (t) 页。

    输入格式

    本题单测试点内有多组测试数据

    第一行是一个整数 (T) ,表示测试数据组数。

    接下来T行,每行有五个整数 (p, a, b, x_1, t) ,表示一组数据。

    输出格式

    对于每组数据,输出一行一个整数表示他最早读到第 (t) 页是哪一天。如果他永远不会读到第 (t) 页,输出 (-1)

    输入输出样例

    输入 #1

    3
    7 1 1 3 3
    7 2 2 2 0
    7 2 2 2 1
    

    输出 #1

    1 
    3 
    -1
    

    说明/提示

    数据规模与约定

    对于全部的测试点,保证:

    • (1 leq T leq 50)
    • (0 leq a, b, x_1, t lt p,2 leq p leq 10^9)
    • (p) 为质数。

    题解

    已知 (a,b,x1,t,p) ,先列出前几项的公式

    [x1 = x_1 \ x2 = ax_1+b\ x3 = a^2x_1+ab+b \ x4 = a^3x_1+a^2b + ab + b\ \ x_n = a^{n-1}x_1 + b(1+a+...+a^{n-1}) \ x_n = a^{n-1}x_1 + b(frac{a^{n-1}-1}{a-1}) \ a^{n-1} = frac{(a-1)t+b}{b+x_1(a-1)} ]

    因为 (p) 是质数,之后使用 (BSGS) 算法进行求解。

    上式中,(a) 不能等于 (1) ,对于 (a=1) ,存在

    [x1 = x_1 \ x2 = x_1+b\ x3 = x_1+2b \ x4 = x_1+3b\ \ x_n = x_1+(n-1)b \ b=frac{x_n-x_1}{n-1} ]

    注意

    • 需要进行 (a = 0) 的所有特殊状态
    • 如果 (x_1=t) 直接输出 (1)

    代码

    #include <map>
    #include <cmath>
    #include <cstdio>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    inline ll multi(ll a,ll b,ll mod){
        ll ret=0;
        if(b<0){
            a=-a;b=-b;
        }
        while(b){
            if(b&1)ret=(ret+a)%mod;
            b>>=1;
            a=(a+a)%mod;
        }
        return (ret%mod+mod)%mod;
    }
    inline ll pow(ll a,ll b,ll mod){
        ll ret=1;
        while(b){
            if(b&1)ret=multi(ret,a,mod);
            b>>=1;
            a=multi(a,a,mod);
        }
        return (ret%mod+mod)%mod;
    }
    inline ll BSGS(ll a,ll b,ll m){
        ll k=ceil(sqrt(m))+1;
        map<ll,ll>M;
        M.clear();
        for(int i=0;i<=k;++i){
            M[b]=i;
            b=multi(b,a,m);
        }
        a=pow(a,k,m);
        ll ret=a;
        for(int i=1;i<=k;++i){
            if(M.count(ret)){
                return i*k-M[ret];
            }
            ret=multi(ret,a,m);
        }
        return -1;// 无解
    }
    int main(){
        int _;
        scanf("%d",&_);
        while(_--){
            ll p,a,b,x1,t;
            scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
            if(x1==t){
                printf("1
    ");
                continue;
            }
            if(a==1){
                if(b==0){
                    if(x1==t)printf("1
    ");
                    else printf("-1
    ");
                }
                else{
                    printf("%lld
    ",(((t-x1)%p+p)%p*pow(b,p-2,p))%p+1);
                }
                continue;
            }
            if(a==0){
                if(x1==t){
                    printf("1
    ");
                }
                else{
                    if(t==b){
                        printf("2
    ");
                    }
                    else printf("-1
    ");
                }
                continue;
            }
            ll aa=a%p;
            ll ss=pow(((a-1)*x1+b)%p,p-2,p);
            ll bb=((((a-1)*t+b)%p*ss)%p+p)%p;
            ll pp=p;
            ll k=BSGS(aa,bb,pp);
            if(k==-1)printf("-1
    ");
            else printf("%lld
    ",(k+1));
        }
        return 0;
    }
    
    新赛季的开始
  • 相关阅读:
    代码题(11)— 链表两数相加
    机器学习(十九)— xgboost初试kaggle
    【js】鼠标跟随效果
    【js】event(事件对象)详解
    【vue】vue +element 搭建项目,this.$nextTick用法
    【vue】vue +element 搭建及开发中项目中,遇到的错误提示
    【vue】vue +element 搭建项目,点击空白处关闭弹窗
    【js】把一个json对象转成想要的数组
    【vue】vue +element 搭建项目,使用el-date-picker组件遇到的坑
    【vue】vue +element 搭建项目,在使用InputNumber 计数器时遇到的问题
  • 原文地址:https://www.cnblogs.com/VagrantAC/p/13282338.html
Copyright © 2011-2022 走看看