版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 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都是整数。按照下面的公式生成出来一系列的整数: 其中mod表示取余操作。
但是这种方法可能导致某两天读的页码一样。
小W要读这本书的第t页,所以他想知道最早在哪一天能读到第t页,或者指出他永远不会读到第t页。
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;
}