zoukankan      html  css  js  c++  java
  • [SDOI2013]随机数生成器-题解

    题目地址【IN

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


    • 简略题意:

    给你初始的P,a,b,x1P,a,b,x_1,生成一个无限长的序列XX,序列的每个元素满足xia×xi1+b(mod P)x_iequiv a imes 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+bsumlimits_{i=0}^{n-2}a^i

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

    i=0n2ai=an11a1 sumlimits_{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 imes left(frac{a^{n-1}-1}{a-1} ight)

    移个项,得到:

    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} imes left(x_1+frac{b}{a-1} ight)\ 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
    ",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
    ",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
    ",ans+1);
    		}
    	}
    	return 0;
    } 
    代码略丑,见谅。
    

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

  • 相关阅读:
    Cooperate with Myself
    A brief introduction of myself
    计算1+11+111+1111+........
    Jav实现F(n)=F(n-1)+F(n-2)+.....+F(1)+1
    查找二维数组中是否有符合的目标值
    排序算法
    时间复杂度
    Java代码实现单例模式
    查找一个字符串中重复出现字符的个数
    null,“”,empty的区别
  • 原文地址:https://www.cnblogs.com/VictoryCzt/p/10053383.html
Copyright © 2011-2022 走看看