【文文殿下】【SDOI2013】随机数生成器 题解

题意

给你个随机数生成器 \(f(x) = a*f(x-1)+b (\mod p)\),给你初始信息\(a,b,t,p,f(1)\),问你几次等于\(t\),如果不等于输出\(-1\).

题解

\[f(n) = a*f(n-1)+b \]

\[f(n) = c*a^{n-1} + \frac {b(a^n-1)}{a-1} \text { where c is an arbitrary parameter} \]

不过上面这个式子咱推不出来,考虑矩阵乘法

\[\begin{pmatrix} a&b\\ 0&1 \end{pmatrix}^x \times \begin{pmatrix} f(1)\\ 1 \end {pmatrix} = \begin{pmatrix} t\\ 1 \end{pmatrix}\]

我们考虑一个BSGS用到矩阵上,就把他做了。
如果你要用这个式子的话

\[a^{i\sqrt{p} + k} = b (\mod p) \]

前面那个转移矩阵的逆矩阵是

\[\begin{pmatrix} \frac{1}{a}&-\frac{b}{a}\\ 0&1 \end{pmatrix} \]

但我懒得用用逆矩阵,直接用下面的这个式子。

\[a^{i\sqrt{p} - k} = b (\mod p) \]

带了矩阵常数贼大,我还懒得手写hashtable,吸着氧过了。
估计思路这么清(zhi)奇(zhang)的人没几个吧。

#include<bits/stdc++.h>
using namespace std;
int p;
int inc(int a,int b) {
	a+=b;
	return a>=p?a-p:a;
}
int dec(int a,int b) {
	a-=b;
	return a<0?a+p:a;
}
int mul(int a,int b) {
	return 1LL*a*b%p;
}
struct qwq {
	int r,c;
	int a[3][3];
	qwq(){
		memset(a,0,sizeof a);
		r=c=0;
	}
	qwq operator * (const qwq& rhs) const {
		qwq ret;
		ret.r = r,ret.c = rhs.c;
		for(int i=1;i<=r;++i) {
			for(int j=1;j<=rhs.c;++j) {
				for(int k=1;k<=c;++k) {
					ret.a[i][j]=inc(ret.a[i][j],mul(a[i][k],rhs.a[k][j]));
				}
			}
		}
		return ret;
	}
	bool operator < (const qwq& rhs) const {
		if(r!=rhs.r) return r<rhs.r;
		if(c!=rhs.c) return c<rhs.c;
		for(int i=1;i<=r;++i)
			for(int j=1;j<=c;++j)
				if(a[i][j]!=rhs.a[i][j])
					return a[i][j]<rhs.a[i][j];
		return 0;
	}
};
int T,a,b,x1,t,ans;
qwq qpow(qwq a,int b) {
	assert(b>=0);
	qwq ret;
	ret.r=a.r,ret.c=a.c;
	for(int i=1;i<=ret.r;++i) ret.a[i][i]=1;
	while(b) {
		if(b&1) ret=ret*a;
		a = a * a;
		b>>=1;
	}
	return ret;
}
bool BSGS(void) {
	map<qwq,int> M;
	M.clear();
	int lmt = sqrt(p)+1;
	ans = 0x3f3f3f3f;
	qwq base;
	base.a[1][1]=a,base.a[1][2]=b,base.a[2][2]=1;
	base.r=base.c=2;
	qwq fn;
	fn.r=2,fn.c=1;
	fn.a[1][1]=t,fn.a[2][1]=1;
	qwq st;
	st.r=2,st.c=1;
	st.a[1][1]=x1,st.a[2][1]=1;
	qwq step = qpow(base,lmt);
	for(int i=1;i<=lmt+1;++i) {
		st = step*st;
		if(!M.count(st)) {
			M[st]=i;
		}
	}
	bool flag = 0;
	for(int i=0;i<=lmt;++i) {
		if(i) fn = base*fn;
		if(M.count(fn)) {
			flag = 1;
			ans = min(ans,M[fn]*lmt-i);
		}
	}
	return flag;
}
int main() {
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d%d%d%d",&p,&a,&b,&x1,&t);
		if(a==0) {
			if(x1==t)
				puts("1");
			else {
				if(b==t) {
					puts("2");
				}
				else {
					puts("-1");
				}
			}
		}
		else {
			if(BSGS()) {
				printf("%d\n",ans+1);
			}
			else {
				puts("-1");
			}
		}
	}
	return 0;
}
posted @ 2019-06-21 21:04  文文殿下  阅读(324)  评论(0编辑  收藏  举报