Description
小 W喜欢读 书,尤其喜欢读 书,尤其喜欢读《约翰克里斯 朵夫》。 最近小 W准备读一本新书,这本一共有 p页, 页码范围为 0..p -1。
小 W很忙,所以每天只能读一页书 。为了使事情有趣一些 ,他打算使用 NOI2012上学习的线性同余法生成 一个序列 ,来决定每天具体读哪一页 。
我们用 Xi来表示通过这种方法生成出来第 i个数 ,也即小 W第 i天会读 哪一页 。这个方法 需要设置 3个参数 a,b,X1,满足 0≤a,b,X1≤p-1,且 a, b,X1都是整数 。按照下面的公式 按照下面的公式生成出来一系列的 整数。
Xi+1= (aXi + b) mod p
其中 mod p 表示前面的数除以 p的余数。
可以发现,这个序列中下一个数总是由上一个数生成的 ,而且每一项都在 0..p -1这个范围内 ,是一个合法的页码。 同时需要注意 ,这种方法有可能导致某两天读的页码完全一样 。
小 W非常急切 地想去读这本书的第t页。所以他想知道, 对于一组给定的 a, b,X1,如果使用线性同余法来生成每一天读的页码, 最早读到第t页是在哪一天,或者指出他永远不会读到第t页。
Input
输入含有多组数据 ,第一行一个正整数T,表示这个测试点内的数据组数。
接下来 T行,每行有 五个整数 p,a,b,X1,t,表示一组数据。 保证 X1和 t都是合法的页码。
Output
共 T行,每行一个整数表示他最早读到第t页是哪一天 。如果他永远不会读到第t页,输出 -1。
Sample Input
3
7 1 1 3 3
7 2 2 2 0
7 2 2 2 1
Sample Output
1
3
-1
Data Constraint
Hint
对于第一组数据,生成的序列为: 3,4,5,6,0…
对于第二 、三 组数据, 生成的序列为: 2,6,0,2…
Solution
BSGS。
套等差数列公式
现在已知x的第n+1项为t(即),求n+1的最小值
对于分母求逆元,对于整个式子BSGS
总结:注意同一个变量不能多用,多开几个变量就好了。同时对于每个相同或相似的过程最好统一一下变量名。
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define I int
#define ll long long
#define F(i,a,b) for(I i=a;i<=b;i++)
#define M 70921
using namespace std;
I T,p,a,b,x,t,m,now,ans,inf=0x7fffffff;
struct node{I v,c;}h[M+10];
void R(I &x){
I w=1;x=0;char c=getchar();
while(c<'0'||c>'9'){if(c=='-') w=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
x*=w;
}
I ksm(ll x,I k){
ll sum=1;
while(k){
if(k&1) sum=(sum*x)%p;
x=(x*x)%p;k>>=1;
}
return sum;
}
I hash(I x){
I k=x%M;
while(h[k].v>=0&&h[k].v!=x) if(++k==M) k=0;
return k;
}
I main(){
freopen("generator.in","r",stdin);
freopen("generator.out","w",stdout);
R(T);
while(T--){
ans=inf;
R(p),R(a),R(b),R(x),R(t);
if(x==t){printf("1\n");continue;}
if(x==0&&b==0){printf("-1\n");continue;}
if(a==0){printf(b==t?"2\n":"-1\n");continue;}
if(a==1){
if(!b){printf("-1\n");continue;}
now=(ll)(t-x+p)%p*ksm(b,p-2)%p;
printf("%d\n",now+1);continue;
}
memset(h,255,sizeof h);
t=((1LL*t*a-t+b)%p+p)%p*ksm(((1LL*x*a-x+b)%p+p)%p,p-2)%p;
m=sqrt(p);
F(j,1,m){
x=hash(t=1LL*t*a%p);
h[x]=node{t,j};
}
now=ksm(a,m);x=1;
F(i,1,m+1){
t=hash(x=1LL*x*now%p);
if(h[t].c>=0) ans=min(ans,i*m-h[t].c+1);
}
printf((ans==inf)?"-1\n":"%d\n",ans);
}
return 0;
}