zoukankan      html  css  js  c++  java
  • [SDOI2013] 随机数生成器

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

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

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

    [x_{i+1} equiv a imes x_i+b pmod p ]

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

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

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


    (m)天第一次读到(t)页,就有(a^mx_1+bfrac{a^m-1}{a-1}equiv tpmod{p}),后面一项是等比数列求和。

    化下式子就是:

    [a^mequiv (t+frac{b}{a-1}) imes (x_1+frac{b}{a-1})^{-1}pmod{p} ]

    (p)又是质数,这就是个(BSGS)的板子式子了。注意这里认为的(a)(>1)(aleq 1)的情况讨论一下就可以了。复杂度(mathcal{O}(Tsqrt{p}log p))

    #include<bits/stdc++.h>
    #define rg register
    #define il inline
    #define cn const
    #define gc getchar()
    #define fp(i,a,b) for(rg int i=(a),ed=(b);i<=ed;++i)
    #define fb(i,a,b) for(rg int i=(a),ed=(b);i>=ed;--i)
    #define go(u) for(rg int i=head[u];~i;i=e[i].nxt)
    #define mp make_pair
    #define fi first
    #define se second
    using namespace std;
    typedef cn int cint;
    typedef pair<int, int> pr;
    il void rd(int &x){
        x = 0;
    	rg int f(1); rg char c(gc);
    	while(c<'0'||'9'<c){if(c=='-')f=-1;c=gc;}
    	while('0'<=c&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=gc;
    	x*=f;
    }
    cint maxn = 34010;
    int T, p, a, b, x, t, inv, sqr, pw[maxn] = {1}, pw2, nw, nw2, pos, ans;
    pr num[maxn];
    il int fpow(int a, int b, int ans = 1){
    	for(; b; b >>= 1, a = 1ll*a*a%p)if(b&1)ans = 1ll*ans*a%p;
    	return ans;
    }
    int main(){
    	rd(T);
    	while(T--){
    		rd(p), rd(a), rd(b), rd(x), rd(t), inv = fpow(a-1, p-2);
    		if(x == t)puts("1");
    		else if(!a){
    			if(x == t)puts("1");
    			else if(b == t)puts("2");
    			else puts("-1");
    		}else if(a == 1){
    			if(b)printf("%lld
    ", 1ll*(t-x+p)*fpow(b, p-2)%p+1);
    			else printf("%d
    ", x == t ? 1 : -1);
    		}
    		else{
    			t = (t+1ll*b*inv)%p*fpow(x+1ll*b*inv%p, p-2)%p, sqr = ceil(sqrt(p)), ans = -1;
    			fp(i, 1, sqr)pw[i] = 1ll*pw[i-1]*a%p, num[i] = mp(pw[i], i);
    			sort(num+1, num+1+sqr), pw2 = fpow(a, sqr), nw = 1;
    			fp(i, 0, p/sqr){
    				nw2 = 1ll*fpow(nw, p-2)*t%p;
    				pos = lower_bound(num+1, num+1+sqr, mp(nw2, 0))->se;
    				if(pw[pos] == nw2){ans = i*sqr+pos+1; break;}
    				nw = 1ll*nw*pw2%p;
    			}
    			printf("%d
    ", ans);
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    zookeeper笔记整理(二)
    zookeeper笔记整理(一)
    SpringBoot源码分析(三)整合MyBatis
    四、MyBatis终结篇(补充中...)
    三、SpringMVC终结篇(补充中...)
    二、SpringAOP终结篇(补充中...)
    一、SpringIOC终结篇(补充中...)
    跳出初学MySQL知识的原理整理(一)
    SpringBoot源码分析(二)启动原理
    一文带你学会基于SpringAop实现操作日志的记录
  • 原文地址:https://www.cnblogs.com/akura/p/14502431.html
Copyright © 2011-2022 走看看