[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;
}
posted @ 2018-08-25 12:10  wxjor  阅读(162)  评论(0编辑  收藏  举报