P3306 [SDOI2013] 随机数生成器

题目描述:

洛谷

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

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

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

$x_{i+1} \equiv a \times x_i+b \pmod p $

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

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

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

数据范围:\(1\leq T\leq 50\), \(0 \leq a, b, x_1, t \lt p\), \(2 \leq p \leq 10^9\), \(p\) 为质数。

solution

我们尝试打一下表,找找规律:

\(x_2 = ax_1 + b\)

\(x_3 = a^2x_1 + ab + b\)

\(x_4 = a^3x_1 + a^2b + ab + b\)

\(x_5 = a^4x_1 + a^3b + a^2b + ab + b\)

\(x_6 = a^5x_1 + a^4b + a^3b + a^2b + ab + b\)

不难发现: \(x_n = a^{n-1}x_1 + \displaystyle\sum_{i=0}^{n-2} a^ib, (x \gt 1)\)

根据等比数列的求和公式则有: \(\displaystyle\sum_{i=0}^{n-2} a^ib = b{1-a^{n-1}\over 1-a}\)

带入可得:\(x_n = a^{n-1}x_1 + {b\over 1-a} (1-a^{n-1})\)

化简一下:

\(x_n = a^{n-1}x_1 + {b\over 1-a} (1-a^{n-1})\)

\(x_n = a^{n-1}x_1 - a^{n-1}{b\over 1-a} + {b\over 1-a}\)

\(B = {b\over 1-a}\), 则原式可以化为:

\(x_n = (x_1-B) a^{n-1} + B\)

\(\because x_n \equiv t\)

\(\therefore (x_1-B) a^{n-1} + B\equiv t\)

\(\therefore (x_1-B)a^{n-1} \equiv t-B \pmod p\)

\(\therefore a^{n-1} \equiv {t-B\over x_1-B} \pmod p\)

\(BSGS\) 算法求解即可。

几个需要特判的点 (被卡到吐):

  • \(x_1 = t\) 的时候,直接输出 \(1\)
  • \(a = 0\) 的时候,如果 \(t = b\) 输出 \(1\) , 反之输出 \(-1\)
  • \(a = 1\) 的时候, 如果 \(b = 0\)\(x \neq t\) 输出 \(-1\), 否则输出 \((t-x) \over b\)

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;
#define int long long
int T,a,b,p,x,t;
inline int read()
{
    int s = 0, w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w;
}
int ksm(int a,int b)
{
	int res = 1;
	for(; b; b >>= 1)
	{
		if(b & 1) res = res * a % p;
		a = a * a % p; 
	}
	return res;
}
int BSGS(int a,int b,int p)
{
	map<int,int> hash;
	int m = sqrt(p) + 1;
	for(int i = 0; i <= m; i++)
	{
		int val = b * ksm(a,i) % p;
		hash[val] = i;
	}
	a = ksm(a,m);
	for(int i = 0; i <= m; i++)
	{
		int val = ksm(a,i);
		int j = hash.find(val) == hash.end() ? -1 : hash[val];
		if(j > 0 && i * m - j > 0) return i * m - j;
	}
	return -1;
}
signed main()
{
	T = read();
	while(T--)
	{
		p = read(); a = read(); b = read(); x = read(); t = read();
		if(x == t){printf("%d\n",1); continue;}
		if(a == 0)
		{
			if(t == x) printf("%d\n",1);
			else if(t == b) printf("%d\n",2);
			else printf("%d\n",-1);
			continue; 
		}
		if(a == 1)
		{
			if(b == 0 && x != t) printf("%d\n",-1);
			else printf("%lld\n",(((t-x+p)%p)*ksm(b,p-2)%p)+1);
			continue;
		}
		int tmp = (1 - a + p) % p;
		int inv = ksm(tmp,p-2);
		t = (t - (b * inv % p) + p) % p;
		x = (x - (b * inv % p) + p) % p;
		t = t * ksm(x,p-2) % p;
		int ans = BSGS(a,t,p);
		if(ans == -1) printf("%d\n",-1);
		else printf("%lld\n",ans+1); 
	}
	return 0;

posted @ 2021-02-27 10:24  genshy  阅读(104)  评论(0)    收藏  举报