BZOJ 3122 SDOI2013 随机数生成器 数论 EXBSGS

42 篇文章 0 订阅

题目大意:给定一个数列X(i+1)=(a*Xi+b)%p 求最小的i>0,使Xi=t

0.0 此题能1A真是太好了

首先讨论特殊情况
若X1=t ans=1
若a=0 ans=b==t?2:-1
若a=1 X1+b*(ans-1)==t (%p) 扩展欧几里得

temp=b/(a-1)
则有
(X(i+1)+temp)=a*(Xi+temp)
Xans=(X1+temp)*a^(ans-1)-temp
其中Xans%p=t
则有
(X1+temp)*a^(ans-1)-temp == t (%p)
两侧同乘a-1得
(a*X1-X1+b)*a^(ans-1) == (a-1)*t+b (%p)

Y=a*X1-X1+b
Z=a*t-t+b
Y*a^(ans-1) == Z(%p)
将Y和p约分
若Z%gcd(Y,p)!=0 return -1

A=a

B=Z*Y^-1

C=p

x=ans-1
A^x==B(%C)

然后就是EXBSGS的模板了0.0 这个模板我再也不想打第二遍了0.0

代码没法看了,诸位理解算法思想就好了0.0

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define M 1001001
using namespace std;
typedef long long ll;
typedef pair<ll,ll> abcd;
ll X,Y,Z,a,b,c,p,t,A,B,C,D;
ll hash_table[M],val[M],tim[M],tot;
int Hash(ll x)
{
	int pos=x%M;
	while(1)
	{
		if(tim[pos]!=tot)
			tim[pos]=tot,hash_table[pos]=-1,val[pos]=0x3f3f3f3f;
		if(hash_table[pos]==-1||hash_table[pos]==x)
			return hash_table[pos]=x,pos;
		else
			++pos,pos%=M;
	}
}
int Get_Hash(ll x)
{
	int pos=x%M;
	while(1)
	{
		if(tim[pos]!=tot)
			tim[pos]=tot,hash_table[pos]=-1;
		if(hash_table[pos]==-1)
			return -1;
		if(hash_table[pos]==x)
			return pos;
		else
			++pos,pos%=M;
	}
}
ll GCD(ll x,ll y)
{
	return y?GCD(y,x%y):x;
}
abcd EXGCD(ll x,ll y)
{
	if(!y) return abcd(1,0);
	abcd temp=EXGCD(y,x%y);
	return abcd(temp.second,temp.first-x/y*temp.second);
}
ll Inverse(ll x)
{
	ll temp=EXGCD(x,C).first;
	return (temp%C+C)%C;
}
ll Extended_Big_Step_Giant_Step()
{
	ll i,m,cnt=0,temp,base=1;
	int pos;
	if(B>=C)
		return -1;
	for(i=0,temp=1%C;i<=50;i++,temp*=A,temp%=C)
		if(temp==B)
			return i;
	D=1;
	while(temp=GCD(A,C),temp!=1)
	{
		if(B%temp)
			return -1;
		++cnt;
		B/=temp;
		C/=temp;
		D*=A/temp;
		D%=C;
	}
	B*=Inverse(D);B%=C;
	m=(ll)ceil(sqrt(C)+1e-5);
	++tot;
	for(i=0,temp=1%C;i<m;i++,temp*=A,temp%=C)
		pos=Hash(temp),val[pos]=min(val[pos],i);
	for(i=1,base=1%C;i<=m;i++,base*=A,base%=C);
	for(i=0,D=1%C;i<m;i++,D*=base,D%=C)
	{
		temp=EXGCD(D,C).first*B;
		temp=(temp%C+C)%C;
		pos=Get_Hash(temp);
		if(~pos)
			return i*m+val[pos]+cnt;
	}
	return -1;
}
ll Deal()
{
	ll temp;
	cin>>p>>a>>b>>X>>t;
	if(X==t) return 1;
	if(!a) return b==t?2:-1; 
	if(a==1)
	{
		t+=p-X;t%=p;
		//b*(ans-1)==t (%p)
		temp=GCD(b,p);
		if(t%temp) return -1;
		b/=temp;t/=temp;p/=temp;
		temp=(EXGCD(b,p).first*t%p+p)%p;
		return temp+1;
	}
	Y=(a*X-X+b)%p;
	Z=(a*t-t+b)%p;
	temp=GCD(Y,p);
	if(Z%temp) return -1;
	Y/=temp;Z/=temp;p/=temp;
	C=p;
	B=Z*Inverse(Y)%p;
	A=a;
	temp=Extended_Big_Step_Giant_Step();
	if(temp==-1)
		return -1;
	return temp+1;
}
int main()
{
	int T;
	for(cin>>T;T;T--)
		cout<<Deal()<<endl;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值