[BZOJ3122][SDOI2013]随机数生成器

bzoj
luogu

题意

线性递推式\(X_{i+1}=aX_i+b\mod\ p\)
给你\(p,a,b,X_1,t\),要你求最小的\(i\)满足\(X_i=t\)或判断无解。

sol

推一下通项公式吧。

\[X_i=aX_{i-1}+b=a(aX_{i-2}+b)+b=...\\=a^{i-1}X_1+b+ab+a^2b+...+a^{i-2}b\\=a^{i-1}X_1+\frac{b(a^{i-1}-1)}{a-1} \]

\(X_n=t\),则有\(a^{n-1}X_1+\frac{b(a^{n-1}-1)}{a-1}=t\)。发现这个式子里只有\(a^{n-1}\)是未知量。直接解出来。
然后就是已知\(a,a^{n-1},p\)\(n\)\(BSGS\)直接上。
要讨论一些特殊情况。
1、\(X_1=t\)时直接返回\(1\)
2、\(a=0\)时,若\(b=t\)则返回\(2\),否则返回\(-1\)
3、\(a=1\)时,若\(b=0\)则返回\(-1\),否则有式子$$X_1+nb\equiv t\mod \ p$$
直接解即可。

code

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<map>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
int fastpow(int a,int b,int mod)
{
	int res=1;
	while (b) {if (b&1) res=1ll*res*a%mod;a=1ll*a*a%mod;b>>=1;}
	return res;
}
map<int,int>M;
int BSGS(int y,int z,int p)
{
	if (y%p==0) return -2;
	int m=sqrt(p)+1;M.clear();
	for (int i=0,t=z;i<=m;++i,t=1ll*t*y%p) M[t]=i;
	for (int i=1,tt=fastpow(y,m,p),t=tt;i<=m;++i,t=1ll*t*tt%p)
		if (M.count(t)) return i*m-M[t];
	return -2;
}
int yyb_solve(int p,int a,int b,int X1,int t)
{
	if (X1==t) return 1;
	if (a==0) {if (b==t) return 2;return -1;}
	if (a==1) {if (b==0) return -1;return 1ll*fastpow(b,p-2,p)*(t-X1+p)%p+1;}
	int c=1ll*b*fastpow(a-1,p-2,p)%p;
	int an=1ll*(t+c)*fastpow(X1+c,p-2,p)%p;
	return BSGS(a,an,p)+1;
}
int main()
{
	int Case=gi();
	while (Case--)
	{
		int p=gi(),a=gi(),b=gi(),X1=gi(),t=gi();
		printf("%d\n",yyb_solve(p,a,b,X1,t));
	}
	return 0;
}
posted @ 2018-04-12 22:10  租酥雨  阅读(204)  评论(0编辑  收藏  举报