BZOJ3122: [Sdoi2013]随机数生成器【BSGS】

3122: [Sdoi2013]随机数生成器

【题目描述】

传送门

【题解】

我们对于题目中的式子变换一下形式,Xi+1+k=a(Xi+k)X_{i+1}+k=a(X_i+k)

然后解出k=ba1k=\frac{b}{a-1}

套上等比数列公式Xn=X1an1+b(an11)a1\large X_n=X_1a^{n-1}+\frac{b(a^{n-1}-1)}{a-1}

cca1a-1的逆元

(X1+bc)an1=t+bc(X1+bc)a^{n-1}=t+bc

求出an1a^{n-1}后,BSGS求出n就可以了.

【代码如下】

#include<map>
#include<cmath>
#include<cstdio>
using namespace std;
typedef long long LL;
LL MOD,m,sp,c,x1,A,B,T,an;
map<LL,LL> hsh;
LL qsm(LL x,LL b){
	LL Mul=1;x%=MOD;
	for(;b;b>>=1,x=x*x%MOD) if(b&1) Mul=Mul*x%MOD;
	return Mul;
} 
LL BSGS(LL a,LL t){
	hsh.clear();hsh[t]=0;
	for(LL i=1,x=a;i<=m;i++,x=x*a%MOD) if(!hsh[x*t%MOD]) hsh[x*t%MOD]=i;
	for(LL i=1,p=qsm(a,m),x=p;i<=m;i++,x=x*p%MOD) if(hsh[x]) return i*m-hsh[x];
	return -2;
}
void solve(){
	c=qsm(A-1,MOD-2);m=ceil(sqrt(MOD));
	an=(T+B*c%MOD)%MOD*qsm(x1+B*c%MOD,MOD-2)%MOD;
	printf("%lld\n",BSGS(A,an)+1);
}
int main(){
	int TT;scanf("%lld",&TT);
	while(TT--){
		scanf("%lld%lld%lld%lld%lld",&MOD,&A,&B,&x1,&T);
		if(T==x1){printf("1\n");continue;}
		if(A==0){if(T==B) printf("2\n");else printf("-1\n");continue;}
		if(A==1&&B==0){printf("-1\n");continue;}
		if(A==1){
			LL Ans=((T-x1)%MOD+MOD)%MOD*qsm(B,MOD-2)%MOD;
			printf("%lld\n",Ans+1);continue;
		}
		solve();
	}
	return 0;
}
posted @ 2019-03-11 11:16  XSamsara  阅读(309)  评论(0编辑  收藏  举报