[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;
}
原文地址:https://www.cnblogs.com/akura/p/14502431.html