BZOJ 3122 SDOI2013 随机数生成器

一大堆边界一开始并不知道,胡乱判了几个之后一直WA

无奈之下只好去下载了数据,然后就疯狂判各种奇怪的边界了

刨去边界问题

首先我们考虑a=1的情况

x1+k*b=t(mod p)

ex_gcd即可解

考虑a>1的情况

令S=X+b/(a-1)

原式就变成了一个等比数列

即S1*a^k=(t+b/(a-1))(mod p)

移项之后BSGS解即可

其他边界都可以O(1)判断

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<map>
#include<cmath>
using namespace std;
 
typedef long long LL;
int T;
LL p,a,b,x1,x,y,d,t,inv;
map<LL,int>Q;
void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y){
    if(b==0){x=1;y=0;d=a;return;}
    ex_gcd(b,a%b,d,y,x);y-=(a/b)*x;
}
LL pow_mod(LL v,LL b){
    LL tmp=1;
    while(b){
        if(b&1)tmp=tmp*v%p;
        v=v*v%p;b>>=1;
    }return tmp;
}
LL log_mod(LL a,LL b,LL n){
    if(a==0&&b==0)return 1;
    if(a==0)return -1;
    LL m=(int)(sqrt(n+0.5))+1;Q.clear();
    LL v=pow_mod(a,m);v=pow_mod(v,n-2);
    LL e=1;Q[1]=0;
    for(int i=1;i<m;++i){
        e=e*a%n;
        if(!Q.count(e))Q[e]=i;
    }
    for(int i=0;i<m;++i){
        if(Q.count(b))return i*m+Q[b]+1;
        b=b*v%n;
    }return -1;
}
 
int main(){
    scanf("%d",&T);
    while(T--){
        scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t);
        if(x1==t){printf("1\n");continue;}
        if(a==0){
            if(b==t){printf("2\n");continue;}
            else {printf("-1\n");continue;}
        }
        if(a==1){
            if(b==0){printf("-1\n");continue;}
            ex_gcd(b,p,d,x,y);
            x1=(t-x1+p)%p;
            if(x1%d!=0){printf("-1\n");continue;}
            x=x*x1;
            x=(x%p+p)%p;
            printf("%lld\n",x+1);
            continue;
        }
        inv=pow_mod(a-1,p-2);
        b=b*inv%p;
        x1=(x1+b)%p;t=(t+b)%p;
        x1=pow_mod(x1,p-2);
        t=t*x1%p;
        printf("%lld\n",log_mod(a,t,p));
    }return 0;
}

  

posted @ 2016-04-14 21:21  _Vertical  阅读(293)  评论(0编辑  收藏  举报