【Luogu】 P3306 [SDOI2013] 随机数生成器

该文主要介绍了如何求解形如Xn=a^(n-1)*X1+b*(a^(n-2)+...+1)的模运算问题,其中涉及等比数列求和公式、模逆元的概念,以及在a=0或a=1时的特殊情况处理。通过扩展欧几里得算法和快速幂优化计算,寻找满足特定模条件的n值。
摘要由CSDN通过智能技术生成

题目链接

点击打开链接

题目解法

首先尝试求出通项公式
多列出几项可以发现: X n = a n − 1 X 1 + a n − 2 b + a n − 3 b + … + b Xn=a^{n-1}X1+a^{n-2}b+a^{n-3}b+…+b Xn=an1X1+an2b+an3b++b
用等比数列求和公式可以得到:
X n = a n − 1 X 1 + a n − 1 − 1 a − 1 b Xn=a^{n-1}X1+\frac{a^{n-1}-1}{a-1}b Xn=an1X1+a1an11b
把所有 a n − 1 a^{n-1} an1 都合并在一起
X n = a n − 1 ( X 1 + b a − 1 ) − b a − 1 Xn=a^{n-1}(X1+\frac{b}{a-1})-\frac{b}{a-1} Xn=an1(X1+a1b)a1b
我们需要求最小的 n n n 满足 X n ≡ t    ( m o d    p ) Xn \equiv t\;(mod \; p) Xnt(modp)
X n Xn Xn 的表达式代入可得:
a n − 1 ( X 1 + b a − 1 ) ≡ t + b a − 1    ( m o d    p ) a^{n-1}(X1+\frac{b}{a-1})\equiv t+\frac{b}{a-1}\;(mod \; p) an1(X1+a1b)t+a1b(modp)
a n − 1 a^{n-1} an1 单独放在左边:
a n − 1 ≡ t + b a − 1 X 1 + b a − 1    ( m o d    p ) a^{n-1}\equiv \frac{t+\frac{b}{a-1}}{X1+\frac{b}{a-1}}\;(mod \; p) an1X1+a1bt+a1b(modp)
我们可以发现这个形式是 a x ≡ b    ( m o d    p ) a^x\equiv b \;(mod\;p) axb(modp)
p p p 是质数,与 a a a 互质,可以用 b s g s bsgs bsgs 求解
同时这道题需要特判 a = 0 a=0 a=0 a = 1 a=1 a=1 的情况,这两类比较简单,但需要特殊考虑
另外需要考虑分母 X 1 + b a − 1 X1+\frac{b}{a-1} X1+a1b 是否存在逆元
我们发现不存在逆元时 X 1 + b a − 1 X1+\frac{b}{a-1} X1+a1b p p p 的倍数,即 X n = − b a − 1    ( n > 1 ) X^n=-\frac{b}{a-1}\;(n>1) Xn=a1b(n>1)
这道题特判比较多,有点坑

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
inline int read(){
	int FF=0,RR=1;
	char ch=getchar();
	for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
	for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
	return FF*RR;
}
int bsgs(int a,int b,int p){
	if(1%p==b%p) return 0;
	int k=sqrt(p)+1;
	unordered_map<int,int> hsh;
	for(int i=0,j=b;i<k;i++)
		hsh[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=1;i<=k;i++){
		j=(LL)j*ak%p;
		if(hsh.count(j)) return i*k-hsh[j];
	}
	return -2;
}
int qmi(int a,int b,int p){
	int res=1;
	for(;b;b>>=1){
		if(b&1) res=(LL)res*a%p;
		a=(LL)a*a%p;
	}
	return res;
}
void exgcd(int a,int b,int &x,int &y){
	if(b==0){
		x=1,y=0;
		return;
	}
	int q=a/b,r=a%b;
	exgcd(b,r,y,x);
	y-=q*x;
}
void work(){
	int p=read(),a=read(),b=read(),X1=read(),t=read();
	if(a==0){//Xn=b(n>1) 
		if(X1==t) puts("1");
		else if(b==t) puts("2");
		else puts("-1");
	}
	else if(a==1){
		if(b==0) puts(X1==t?"1":"-1");
		else{
			int x,y;
			exgcd(b,p,x,y);
			if(x<0) x+=p;
			x=((LL)x*(t-X1)%p+p)%p;
			printf("%d\n",x+1);
		}
	}
	else{
		int fm=(X1+(LL)b*qmi(a-1,p-2,p)%p)%p;
		if(fm%p==0){
			if(X1==t) puts("1");
			else if((LL)-b*qmi(a-1,p-2,p)%p+p==t) puts("2");
			else puts("-1");
		}
		else{
			int fz=(t+(LL)b*qmi(a-1,p-2,p)%p)%p;
			printf("%d\n",bsgs(a,(LL)fz*qmi(fm,p-2,p)%p,p)+1);
		}
	}
}
int main(){
	int T=read();
	while(T--) work();
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值