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

版权声明:转载注明出处,谢谢,有问题可以向博主联系 https://blog.csdn.net/VictoryCzt/article/details/84590758

题目地址【IN

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


  • 简略题意:

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


首先推一波式子:

x 2 = a x 1 + b x 3 = a x 2 + b = a 2 x 1 + a b + b x 4 = a x 3 + b = a 3 x 1 + a 2 b + a b + b x n = a x n 1 + b = a n 1 x 1 + b i = 0 n 2 a i 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 = 0 n 2 a i = a n 1 1 a 1 \sum\limits_{i=0}^{n-2}a^i=\frac{a^{n-1}-1}{a-1}

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

原式就变成了如下:

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

移个项,得到:

x n = a n 1 x 1 + a n 1 b a 1 b a 1 x n + b a 1 = a n 1 × ( x 1 + b a 1 ) a n 1 = x n + b a 1 x 1 + b a 1 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}}

令右边为 v a l val ,原式就为 a n 1 = v a l a^{n-1}=val

现在我们相当于知道了 x n = t x_n=t ,然后去求是否存在一个 n n 使其满足,就变成了 B S G S BSGS 板子题了。(不会BSGS的先去学,全称叫 B a b y S t e p G i a n t S t e p Baby Step Giant Step 离散对数的大步小步算法)

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

复杂度 O ( T ( P + l o g P + m a p ) ) 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;
} 
代码略丑,见谅。

其他关于 B S G S BSGS 以及 E x B S G S ExBSGS 的题目:

猜你喜欢

转载自blog.csdn.net/VictoryCzt/article/details/84590758