[SDOI2013]随机数生成器(BSGS)

这题妙啊,我们做这道题遇到的首先一个门槛就是推式子:

[X_{i+1}=aX_{i}+b ]

我们考虑两边同时加上(frac{b}{a-1}),这样我们就构造出了一个等比数列:

[X_{i+1}+frac{b}{a-1}=a(X_i+frac{b}{a-1})(mod:p) ]

然后就是简单的等比数列求第(n)项:

[X_{n}+frac{b}{a-1}=a^{n-1}(X_1+frac{b}{a-1})(mod:p) ]

上式只有(n)是未知的,我们移项可得:

[a^{n-1}equiv(X_n+b*inv(a-1))*inv(X_1+b*inv(a-1))(mod:p) ]

我们求(n)就直接用bsgs就好了,注意明显的特殊数据就直接特判输出答案,看代码

#pragma GCC optimize(2)
#pragma G++ optimize(2)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll T,C;
ll powmod(ll x,ll y,ll mod)
{
	ll sum=1;
	while(y)
	{
		if(y&1)
		{
			sum=sum*x%mod;
		}
		x=x*x%mod;
		y>>=1;
	}
	return sum;
}
map<ll,ll> mp;
void bsgs(ll x,ll y,ll mod)
{
	ll i,j;
	if(x%mod==0)
	{
		printf("-1
");
		return;
	}
	mp.clear();
	ll m=sqrt(mod)+1,t,tt;
	for(i=0,t=y;i<m;++i,t=t*x%mod) mp[t]=i;
	for(i=1,tt=powmod(x,m,mod),t=tt;i<=m;i++,t=t*tt%mod)
	{
		j=mp.find(t)==mp.end()?-1:mp[t];
		if(j>=0&&i*m-j>=0)
		{
			printf("%lld
",i*m-j+1);
			return;
		}
	}
	printf("-1
");
}
int main()
{
	ll i,j,p,a,b,X1,t;
	scanf("%lld",&T);
	while(T--)
	{
		scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&X1,&t);
		if(X1==t){puts("1");continue;}
		if(a==0){puts(t==b?"2":"-1");continue;}
		if(a==1&&b==0){puts("-1");continue;}
		if(a==1){
			ll ny=powmod(b,p-2,p);
			ll ans=((((t-X1)%p+p)%p)*ny%p)%p;
			printf("%lld
",ans+1);continue;
		}
		ll u=b%p*powmod(a-1,p-2,p);
		ll cc=(X1+u)%p;
		C=(t+u)%p*powmod(cc,p-2,p)%p;
		bsgs(a,C%p,p);
	}
	return 0;
} 
原文地址:https://www.cnblogs.com/yzxx/p/11700388.html