bzoj3122 [Sdoi2013]随机数生成器 BSGS

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/83064319

Description


小W喜欢读书,尤其喜欢读《约翰克里斯朵夫》。最近小W准备读一本新书,这本书一共有P页,页码范围为0⋯P−1

小W很忙,所以每天只能读一页书。为了使事情有趣一些,他打算使用NOI2012上学习的线性同余法生成一个序列,来决定每天具体读哪一页。

我们用Xi来表示通过这种方法生成出来的第iii个数,也即小W第i天会读哪一页。这个方法需要设置3个参数a,b,X1,满足0≤a,b,X1≤p−1,且a,b,X1都是整数。按照下面的公式生成出来一系列的整数: X i + 1 a X i + b ( m o d p ) X_{i+1} \equiv aX_i+b \pmod p 其中mod表示取余操作。

但是这种方法可能导致某两天读的页码一样。

小W要读这本书的第t页,所以他想知道最早在哪一天能读到第t页,或者指出他永远不会读到第t页。

0 a P 1 , 0 b P 1 , 2 P 1 0 9 0\leq a\leq P-1,0\leq b\leq P-1,2\leq P\leq 10^9

Solution


课本内容。。对这个数列求和就行了,然后做bsgs
特判很多

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
#define rep(i,st,ed) for (int i=st;i<=ed;++i)
#define drp(i,st,ed) for (int i=st;i>=ed;--i)

std:: map <int,int> map;

int p;

int ksm(int x,int dep) {
	const int MOD=p;
	int ret=1;
	for (;dep;dep>>=1) {
		(dep&1)?(ret=1LL*ret*x%MOD):0;
		x=1LL*x*x%MOD;
	}
	return ret;
}

int BSGS(int a,int b) {
	map.clear();
	const int MOD=p;
	int r=sqrt(MOD)+1,tmp=1LL*b*ksm(a,MOD-2)%MOD;
	int wjp=ksm(a,r);
	rep(i,0,r) {
		tmp=1LL*tmp*a%MOD;
		map[tmp]=i;
	}
	tmp=1;
	rep(i,1,r) {
		tmp=1LL*tmp*wjp%MOD;
		int lxf=map[tmp];
		if (lxf) return r*i-lxf;
	}
	return -2;
}

int main(void) {
	freopen("data.in","r",stdin);
	freopen("myp.out","w",stdout);
	int T; scanf("%d",&T);
	for (int a,b,x,t;T--;) {
		scanf("%d%d%d%d%d",&p,&a,&b,&x,&t);
		const int MOD=p;
		if (x==t) {
			puts("1");
			continue;
		}
		if (a==0) {
			if (b==t) puts("2");
			else puts("-1");
			continue;
		}
		if (a==1) {
			if (b==0) puts("-1");
			else {
				t=((t-x)%MOD+MOD)%MOD;
				t=1LL*t*ksm(b,MOD-2)%MOD;
				printf("%d\n", t+1);
			}
			continue;
		}
		int c=(1LL*b*ksm(a-1,MOD-2)%MOD+t)%MOD;
		c=1LL*c*ksm((1LL*b*ksm(a-1,MOD-2)%MOD+x)%MOD,MOD-2)%MOD;
		printf("%d\n", BSGS(a,c)+1);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/83064319