bzoj 3122 [Sdoi2013]随机数生成器(逆元,BSGS)

时间:2023-03-08 16:56:25
bzoj 3122 [Sdoi2013]随机数生成器(逆元,BSGS)

Description

bzoj 3122 [Sdoi2013]随机数生成器(逆元,BSGS)

Input

输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数。 
 
接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据。保证X1和t都是合法的页码。

注意:P一定为质数

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

HINT

0<=a<=P-1,0<=b<=P-1,2<=P<=10^9

【思路】

逆元,BSGS算法

首先特判:a=0,a=1,当a=1时,序列为:

x1,x1+b,x1+2*b

即(x1+(n-1)*b) mod p=t,用个乘法逆元可以求出,当逆元为0的时候无解输出-1。

当a>=2时

可以得到通项公式:

xn=[
a^n-1 *(x1+b/(a-1))-b/(a-1) ] mod p

若满足xn=t,则有

a^n-1 = (b* (a-1)^-1 +t) * (b*(a-1)^-1+x1)^-1
mod p

于是可以用BSGS算法求n-1。

需要注意的是各种取模p一定要有。

【代码】

 #include<map>
#include<cmath>
#include<cstdio>
#include<iostream>
using namespace std; typedef long long LL;
const int N = 1e4+; LL pow(LL x,LL p,LL MOD) {
LL ans=;
while(p) {
if(p&) ans=(ans*x)%MOD;
x=(x*x)%MOD;
p>>=;
}
return ans;
}
map<LL,int> mp;
LL BSGS(LL a,LL b,LL MOD) {
a%=MOD;
int m=sqrt(MOD)+; mp.clear();
LL am=pow(pow(a,m,MOD),MOD-,MOD);
LL x=; mp[]=;
for(int i=;i<m;i++) {
x=(x*a)%MOD;
if(!mp.count(x)) mp[x]=i;
}
for(int i=;i<m;i++) {
if(mp.count(b)) return i*m+mp[b];
b=(b*am)%MOD;
}
return -;
} LL p,a,b,x1,t; int main() {
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
int T;
scanf("%d",&T);
while(T--) {
cin>>p>>a>>b>>x1>>t;
LL c=pow(a-,p-,p),d,x,y,con,inv;
if(x1==t) puts(""); else
if(!a) {
if(t==b) puts("");
else puts("-1");
} else
if(a==) {
inv=pow(b,p-,p);
if(!inv) puts("-1");
else printf("%lld\n",((inv*(t-x1+p)%p)+p)%p+);
} else {
con=((((b*c+t)%p)*(pow((x1+b*c)%p,p-,p)))%p+p)%p;
printf("%lld\n",BSGS(a,con,p)+);
}
}
return ;
}