【bzoj3122】【SDOI2013】 隨機數生成器

公式其實挺容易推的,看見zyf推的好複雜= =,其實直接代秦九昭算法,然後用等比數列求和就能推出來,推到最後應該是
Xn+b/a−1≡an−1(X1+b/a−1)(modp)
然後會發現除了a^n-1其他都是常數,注意要求逆元
然後直接BSGS就好了,求逆元可以用exgcd也可以用a^(p-2)求.
代碼找不到了/(ㄒoㄒ)/~~,我貼zyf神犇的好了畢竟模板都是照着她寫的.

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
using namespace std;
#define LL long long

LL T,P,a,b,x1,t;
LL ny1,ny2,val1,val2,val3;
LL ans;
map <LL,LL> hash;

inline LL fast_pow(LL a,LL p){
    LL ans=1;
    for (;p;p>>=1,a=a*a%P)
      if (p&1)
        ans=ans*a%P;
    return ans;
}

inline LL BSGS(LL a,LL b){
    LL m=ceil(sqrt(P));
    LL a_m=fast_pow(a,m);
    hash.clear();

    LL mul=1;
    LL val=mul*b%P;
    hash[val]=0;
    for (LL j=1;j<=m;++j){
        mul=mul*a%P;
        val=mul*b%P;
        hash[val]=j;
    }

    mul=1;
    for (LL i=1;i<=m;++i){
        mul=mul*a_m%P;
        if (hash[mul]){
            LL x=i*m-hash[mul];
            return x+1;
        }
    }
    return -1;
}

int main(){
    scanf("%lld",&T);
    while (T--){
        scanf("%lld%lld%lld%lld%lld",&P,&a,&b,&x1,&t);

        //一坨特判
        if (t==x1){
            printf("1\n");
            continue;
        }
        if (a==0){
            if (t==b) printf("2\n");
            else printf("-1\n");
            continue;
        }
        if (a==1&&b==0){
            printf("-1\n");
            continue;
        }
        if (a==1){
            int nyb=fast_pow(b,P-2);
            ans=((((t-x1)%P+P)%P)*nyb%P)%P;
            printf("%lld\n",ans+1);
            continue;
        }


        ny1=fast_pow(a-1,P-2);
        val1=b*ny1%P;

        val2=(x1%P+val1)%P;
        ny2=fast_pow(val2,P-2);

        val3=(t+val1)%P;
        b=(val3*ny2)%P;

        ans=BSGS(a,b);
        printf("%lld\n",ans);
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章