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

题目地址【IN

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


  • 简略题意:

给你初始的 P , a , b , x 1 P,a,b,x_1 P,a,b,x1,生成一个无限长的序列 X X X,序列的每个元素满足 x i ≡ a × x i − 1 + b ( m o d   P ) x_i\equiv a\times x_{i-1}+b(mod\ P) xia×xi1+b(mod P),询问你一个数字 t t t,最早在序列的哪个位置出现,输出位置,如果没有出现则输出 − 1 -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 x2=ax1+bx3=ax2+b=a2x1+ab+bx4=ax3+b=a3x1+a2b+ab+bxn=axn1+b=an1x1+bi=0n2ai

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

∑ 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} i=0n2ai=a1an11

题外话:证明 a n − 1 − 1 a^{n-1}-1 an11 a − 1 a-1 a1的倍数(当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) an11=(a1)(an2+an3++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) (an+an1++a)(an1+an2++1),中间消掉就变成了 a n − 1 − 1 a^{n-1}-1 an11,又因为 a n − 2 + a n − 3 + ⋯ + a + 1 a^{n-2}+a^{n-3}+\cdots+a+1 an2+an3++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) xn=an1x1+b×(a1an11)

移个项,得到:

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}} xn=an1x1+a1an1ba1bxn+a1b=an1×(x1+a1b)an1=x1+a1bxn+a1b

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

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

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

复杂度 O ( T ( P + l o g P + m a p 常 数 ) ) O(T(\sqrt{P}+logP+map常数)) O(T(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 BSGS以及 E x B S G S ExBSGS ExBSGS的题目:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VictoryCzt

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值