[SDOI2013]随机数生成器-题解

题目地址【IN

很久没写BSGS了,找个板子练练手吧


  • 简略题意:

给你初始的P,a,b,x1P,a,b,x_1,生成一个无限长的序列XX,序列的每个元素满足xia×xi1+b(mod P)x_i\equiv a\times x_{i-1}+b(mod\ P),询问你一个数字tt,最早在序列的哪个位置出现,输出位置,如果没有出现则输出1-1


首先推一波式子:

x2=ax1+bx3=ax2+b=a2x1+ab+bx4=ax3+b=a3x1+a2b+ab+bxn=axn1+b=an1x1+bi=0n2ai x_2=ax_1+b\\ x_3=ax_2+b=a^2x_1+ab+b\\ x_4=ax_3+b=a^3x_1+a^2b+ab+b\\ \cdots\\ x_n=ax_{n-1}+b=a^{n-1}x_1+b\sum\limits_{i=0}^{n-2}a^i

我们现在就的到了这个序列的通项公式,然后用等比数列求和公式简化一下,得到:

i=0n2ai=an11a1 \sum\limits_{i=0}^{n-2}a^i=\frac{a^{n-1}-1}{a-1}

题外话:证明an11a^{n-1}-1a1a-1的倍数(当a为正整数)
因为an11=(a1)(an2+an3++a+1)a^{n-1}-1=(a-1)(a^{n-2}+a^{n-3}+\cdots+a+1)
展开后面就变成了(an+an1++a)(an1+an2++1)(a^n+a^{n-1}+\cdots+a)-(a^{n-1}+a^{n-2}+\cdots+1),中间消掉就变成了an11a^{n-1}-1,又因为an2+an3++a+1a^{n-2}+a^{n-3}+\cdots+a+1为正整数,所以成立。

原式就变成了如下:

xn=an1x1+b×(an11a1) x_n=a^{n-1}x_1+b\times \left(\frac{a^{n-1}-1}{a-1}\right)

移个项,得到:

xn=an1x1+an1ba1ba1xn+ba1=an1×(x1+ba1)an1=xn+ba1x1+ba1 x_n=a^{n-1}x_1+\frac{a^{n-1}b}{a-1}-\frac{b}{a-1}\\ x_n+\frac{b}{a-1}=a^{n-1}\times \left(x_1+\frac{b}{a-1}\right)\\ a^{n-1}=\frac{x_n+\frac{b}{a-1}}{x_1+\frac{b}{a-1}}

令右边为valval,原式就为an1=vala^{n-1}=val

现在我们相当于知道了xn=tx_n=t,然后去求是否存在一个nn使其满足,就变成了BSGSBSGS板子题了。(不会BSGS的先去学,全称叫BabyStepGiantStepBaby Step Giant Step离散对数的大步小步算法)

但是注意,由于式子分母不能为00所以a=1a=1特判,等比数列中的等比值a=0a=0时也要特判。

复杂度O(T(P+logP+map))O(T(\sqrt{P}+logP+map常数))

代码:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int T;
ll P,a,b,X1,t;
namespace HASH_LIST{
	const int M=1e5+10,Mod=91799;
	struct ss{
		int to,last;ll v,p;
		ss(){}
		ss(int a,int b,ll c,ll d):to(a),last(b),v(c),p(d){}
	};
	struct Hash_List{
		ss g[M];
		int head[M],cnt,tot;
		void add(int a,int b,ll c,ll d){g[++cnt]=ss(b,head[a],c,d);head[a]=cnt;}
		void clear(){memset(head,0,sizeof(head));cnt=tot=0;}
		void insert(ll a,ll b){
			int t=a%Mod;
			add(t,++tot,a,b);
		}
		ll find(ll a){
			int t=a%Mod;
			for(int i=head[t];i;i=g[i].last){
				if(g[i].v==a) return g[i].p;
			}
			return -1;
		}
	};
	ll fpow(ll a,ll b,ll c){
		ll res=1;
		for(;b;b>>=1,a=(a*a)%c){
			if(b&1)res=(res*a)%c;
		}	
		return res;
	}
	ll exgcd(ll a,ll b,ll &x,ll &y){
		if(!b){x=1;y=0;return a;}
		ll t=exgcd(b,a%b,y,x);
		y-=(a/b)*x;return t;
	}
	ll Inv(ll a,ll b){
		ll xx,yy;
		exgcd(a,b,xx,yy);
		return (xx%b+b)%b;
	}
	ll gcd(ll a,ll b){
		return b?gcd(b,a%b):a;
	}
}
using namespace HASH_LIST;
Hash_List mp;//手写hash表

ll BSGS(ll a,ll b){
	mp.clear();
	ll now=(ll)sqrt(P)+1;
	ll res=b;
	for(ll i=1;i<=now;i++){
		res=res*a;if(res>=P)res%=P;
		mp.insert(res,i);
	}
	a=fpow(a,now,P);
	if(!a){return !b?1:-1;}
	res=1;ll ans=0;
	for(ll i=1;i<=now;i++){
		res=res*a;if(res>=P)res%=P;
		ll tt=mp.find(res);
		if(tt>=0){
			ans=(i*now-tt)%P;if(ans<0)ans+=P;
			return ans;
		}
	}
	return -1;
}

int main(){
	for(scanf("%d",&T);T--;){
		scanf("%lld%lld%lld%lld%lld",&P,&a,&b,&X1,&t);
		if(X1==t%P){puts("1");continue;}
		if(!b){
			ll val=t*Inv(X1,P)%P;
			ll ans=BSGS(a,val);
			if(ans==-1) puts("-1");
			else printf("%lld\n",ans+1);
			continue;
		}
		if(!a){
			if(t%P==b)puts("2");else puts("-1");
		}else if(a==1){
			ll day=(t-X1)*Inv(b,P)%P;
			if(day<0)(day%=P)+=P;
			printf("%lld\n",day+1);
		}else{
			ll Inv_a=b*Inv(a-1,P)%P;
			ll val=((t+Inv_a)%P)*Inv((X1+Inv_a)%P,P)%P;
			ll ans=BSGS(a,val);
			if(ans==-1) puts("-1");
			else printf("%lld\n",ans+1);
		}
	}
	return 0;
} 
代码略丑,见谅。

其他关于BSGSBSGS以及ExBSGSExBSGS的题目:

posted @ 2018-11-28 19:23  VictoryCzt  阅读(187)  评论(0编辑  收藏  举报