[BZOJ3122] [Sdoi2013]随机数生成器
[BZOJ3122] [Sdoi2013]随机数生成器
Description
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
试题分析
发现\(x_i=a^k \times x_1+a^{k-1}b+\ldots+a^0 b\)。
那么只需要后面用等比数列化简一下,然后暴力推式子就可以了。
注意特判一些特殊情况。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<map>
#include<cmath>
#include<algorithm>
using namespace std;
#define LL long long
inline LL read(){
LL x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}
const LL INF = 2147483600;
const LL MAXN = 100010;
LL T; LL P,A,B,C,X,t;
map<LL,LL> mp;
inline LL Pow(LL a,LL b){
LL res=1;
while(b){
if(b&1) res=res*a%P;
a=a*a%P; b>>=1;
} return res;
}
inline LL inv(LL x){
x=(x%P+P)%P;
return Pow(x,P-2)%P;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
T=read();
while(T--){
P=read(),A=read(),B=read(),X=read(),t=read();
if(X==t){printf("%d\n",1); continue;}
if(!A){if(B!=t) printf("%d\n",-1); else printf("%d\n",2); continue;}
if(A==1){if(!B) puts("-1"); else printf("%lld\n",(t-X+P)%P*inv(B)%P+1); continue;}
mp.clear(); LL k=(t+B*inv(A-1)%P)%P*inv(X+B*inv(A-1)%P)%P;
LL m=ceil(sqrt(P)); LL tmp=k;
mp[tmp]=1; for(LL i=1;i<=m;i++){
tmp=tmp*A%P; mp[tmp]=i+1;
} tmp=1; LL y=Pow(A,m); bool flag=false;
for(LL i=1;i<=m+1;i++){
tmp=tmp*y%P; LL pos=mp[tmp];
if(pos){
printf("%lld\n",i*m-pos+2); flag=true; break;
}
} if(!flag) puts("-1");
}
return 0;
}
你——悟到了么?