2526. 随机数生成器

题目链接

2526. 随机数生成器

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

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

\(W\) 很忙,所以每天只能读一页书。

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

我们用 \(X_i\) 来表示通过这种方法生成出来的第 \(i\) 个数,也即小 \(W\)\(i\) 天会读哪一页。

这个方法需要设置 \(3\) 个参数 \(a,b,X_1\),满足 \(0 \le a,b,X_1 \le p-1\),且 \(a,b,X_1\) 都是整数。

按照下面的公式生成出来一系列的整数。

\(X_{i+1}=(aX_i+b) \bmod p\)

其中 \(\bmod p\) 表示前面的数除以 \(p\) 的余数。

可以发现,这个序列中下一个数总是由上一个数生成的,而且每一项都在 \(0..p-1\) 这个范围内,是一个合法的页码。

同时需要注意,这种方法有可能导致某两天读的页码完全一样。

\(W\) 非常急切的想去读这本书的第 \(t\) 页。

所以他想知道,对于一组给定的 \(a,b,X_1\),如果使用线性同余法来生成每一天读的页码,最早读到第 \(t\) 页是在哪一天,或者指出他永远不会读到第 \(t\) 页。

输入格式

输入含有多组数据,第一行一个正整数 \(T\),表示这个测试点内的数据组数。

接下来 \(T\) 行,每行有五个整数 \(p,a,b,X_1,t\),表示一组数据。保证 \(X_1\)\(t\) 都是合法的页码。

注意:\(P\) 一定为质数。

输出格式

\(T\) 行,每行一个整数表示他最早读到第 \(t\) 页是哪一天。

如果他永远不会读到第 \(t\) 页,输出 \(-1\)

数据范围

\(0 \le a \le p-1\),
\(0 \le b \le p-1\),
\(2 \le p \le 10^9\)

输入样例:

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

输出样例:

1
3
-1

解题思路

bsgs

对于 \(X_{i+1}=(aX_i+b) \bmod p\),设 \(X_{i+1}+c=a(X_i+c)\),解得 \(c=b/(a-1)\),则有 \(X_{n}+b/(a-1)=a^{n-1}\times (X_1+b/(a-1))\),其中 \(X_n=t\),转换得 \(a^{n-1}\equiv \frac{t+b/(a-1)}{X_1+b/(a-1)}(\bmod p)\),即 bsgs 模板题,另外这里值得一提的是,\(X_1+b/(a-1)\) 可能是 \(p\) 的倍数,即不能用逆元处理,特判这部分后另外要求 \(a^{n-1}\bmod p\) 是一个整数,则 \(t+b/(a-1)\) 也必须要是 \(p\) 的倍数才可能有解,而 \(X_1,t\) 的范围都小于 \(p\),则上下只存在相等的情况,即 \(a^{n-1}=1\),则 \(n=1\)

  • 时间复杂度:\(O(\sqrt{p})\)

代码

// Problem: 随机数生成器
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/2528/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
//#define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int T,p,a,b,x,t;
int ksm(int a,int b,int p)
{
	int res=1%p;
	while(b)
	{
		if(b&1)res=1ll*res*a%p;
		a=1ll*a*a%p;
		b>>=1;
	}
	return res;
}
int inv(int a,int p)
{
	return ksm(a,p-2,p);
}
int bsgs(int a,int b,int p)
{
	b%=p;
	if(1==b)return 0;
	unordered_map<int,int> hash;
	int k=sqrt(p)+1;
	for(int i=0,j=b;i<k;i++)
	{
		hash[j]=i;
		j=(LL)j*a%p;
	}
	int ak=1;
	for(int i=1;i<=k;i++)ak=(LL)ak*a%p;
	for(int i=1,j=ak;i<=k;i++)
	{
		if(hash.count(j))return i*k-hash[j];
		j=(LL)j*ak%p;
	}
	return -1;
}
int main()
{
    for(cin>>T;T;T--)
    {
    	cin>>p>>a>>b>>x>>t;
    	if(a==0)
    	{
    		if(x==t)puts("1");
    		else if(b==t)puts("2");
    		else
    			puts("-1");
    	}
    	else if(a==1)
    	{
    		if(b==0)puts(x==t?"1":"-1");
    		else
    			cout<<(LL)inv(b,p)*(t-x+p)%p+1<<'\n';
    	}
    	else
    	{
    		int A=(LL)b*inv(a-1,p)%p;
    		int B=(x+A)%p;
    		if(B==0)
    			puts((-A+p)%p==t?"1":"-1");
    		else
    		{
    			int C=(t+A)%p;
    			int res=bsgs(a,(LL)C*inv(B,p)%p,p);
    			if(res>=0)cout<<res+1<<'\n';
    			else
    				puts("-1");
    		}
    	}
    }
    return 0;
}
posted @ 2022-10-14 23:36  zyy2001  阅读(74)  评论(0编辑  收藏  举报