【SDOI2013】【BZOJ】【P3122】【随机数生成器】【Baby Step Giant Step】

传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3122

题解:

把数列化简:

x[i+1]=ax[i]+b(mod p)

==>x[i+1]+b/(a-1)=a(x[i]+b/(a-1))] (mod p)

==>x[t]+b/(a-1)=a^(t-1)(x1+b/(a-1)) (mod p)

==>(x[t]+b*inv(a-1))*inv(x1+b*inv(a-1))=a^(t-1)(mod p)  inv表示逆元

然后Baby Step Giant Step

注意a=1 a=0 b=0  x1=xn等特判

奇丑无比的代码:

/*
	ID:zky
	OJ:BZOJ
	Index:3122
	Language:C++
*/
#include<map>
#include<cmath>
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long lld;
lld x1,xn,a,b,p;

map<lld,lld>hash;
lld power(lld x,lld k,lld p){
	lld res=1;
	if(k==0)return 1;
	res=power(x,k/2,p)%p;
	res=(res%p)*(res%p)%p;
	if(k&1)res=(res%p)*(x%p)%p;
	return res;
}
lld inv(lld x){
	return power(x,p-2,p);
}
void work3(){
	//xn=(a*x1+b)%p
	//==>xn+b/(a-1)=a^(t-1)*(x1+b/(a-1)) mod p
	//==>(xn+b*inv(a-1))*inv(x1+b*inv(a-1))=a^(t-1)mod p
	//==>~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
	lld tmp=b*inv(a-1)%p;
	xn=(xn+tmp)%p;
	x1=(x1+tmp)%p;	
	lld N=xn*inv(x1)%p;
	
	a%=p;N%=p;
	if(!a&&!N){
		cout<<1<<endl;
		return;
	}
	if(!a){
		cout<<-1<<endl;
		return;
	}
	//a^(t-1)=N(mod p)
	//solve t!
	//k=t-1
	//k=im+j
	//for j=0 -> m-1 in hash
	//a^im*a^j=N(mod p)
	//v=inv(a^m)=power(a,p-m-1,p)
	//a^j=N*v^i(mod p) for i,watch j in hash
	
	lld m=ceil(sqrt(p));
	lld v=power(a,p-m-1,p);
	lld ans=-1;
	hash[1]=m+1;
	lld e=a;
	for(int j=1;j<=m;j++){
		if(!hash[e])hash[e]=j;
		e=(e%p*(a%p))%p;
	}
	for(int i=0;i<m;i++){
		lld j=hash[N];
		if(j){			
			if(j==m+1)j=0;
			ans=i*m+j;
			break;
		}
		N=(N*v)%p;
	}
	hash.clear();
	if(ans==0){
		cout<<p<<endl;
		return;
	}
	if(ans==-1)
	cout<<ans<<endl;	
	else
	cout<<ans+1<<endl;
	
}
void exgcd(lld a,lld b,lld &x,lld &y){  
    if(b==0){  
        x=1;y=0;  
    }else{  
        exgcd(b,a%b,x,y);  
        int t=x;  
        x=y;  
        y=t-a/b*y;  
    }     
} 
lld gcd(lld a,lld b){
	if(!b)return a;return gcd(b,a%b);
}
void work2(){  
	lld n=xn-x1+b;	
    lld d=gcd(b,p);  
    if(n%d){  
        cout<<-1<<endl;  
        return;  
    }  
    lld r,s;  
    exgcd(b,p,r,s);  
    r=r*n/d;  
    r=(r+p)%p;  
    while(r<=0)r+=p;  
    //while(r<0)r+=p;  
    cout<<r<<endl;  
}  
void work(){  
	lld z=xn%p*inv(x1)%p;
	lld y=a;
    y%=p;z%=p;    
    if(!y&&!z){cout<<"1"<<endl;return;}  
    if(!y){cout<<"-1"<<endl;return;}  
    lld m=ceil(sqrt(p));  
    lld v=power(y,p-m-1,p); 
    lld e=1;  
    hash[1]=m+1;  
    for(lld i=1;i<=m;i++){  
        e=(e*y)%p;  
        if(!hash[e])hash[e]=i;  
    }  
    lld ans=-1;  
    for(lld i=0;i<m;i++){  
        lld j=hash[z];  
        if(j){  
            if(j==m+1)j=0;  
            ans=i*m+j;    
            break;  
        }  
        z=(z*v)%p;//  
    }  
    hash.clear();   
	if(ans==0){
		cout<<p<<endl;
		return;
	}
    if(ans==-1)cout<<"-1"<<endl;  
    else cout<<ans+1<<endl;  

}
int main(){
	lld T;
	cin>>T;
	while(T--){
		cin>>p>>a>>b>>x1>>xn;
		if(x1==xn){
			cout<<1<<endl;
			continue;
		}
    	if(a==0&&b==0){
    		cout<<-1<<endl;
    		continue;
    	}else 
    	if(a==0){
    		if(xn%p==x1%p)cout<<1<<endl;
    		else if(xn==b)cout<<2<<endl;
    		else cout<<-1<<endl;
    		continue;
    	}else
    	if(a==1&&b==0){
    		if(x1==xn)cout<<1<<endl;
    		else cout<<-1<<endl;
    		continue;
    	}else
    	if(a==1){
    		work2();
    		continue;
    	}else if(b==0){
    		work();
    	}
		else work3();
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值