1. 程式人生 > 實用技巧 >BZOJ-3122 [Sdoi2013]隨機數生成器(BSGS)

BZOJ-3122 [Sdoi2013]隨機數生成器(BSGS)

題目描述

  有四個引數 \(p,a,b,x_1\),滿足 \(0\leq a,b,x_1<p\),按照下面的式子生成一系列整數:

\[x_{i+1}\equiv a\times x_i+b\pmod {p} \]

  給出一個數字 \(t\),求出 \(x_i=t\) 的最小下標 \(i\)

  資料範圍:\(1\leq T\leq 50,0\leq a,b,x_1,t<p,2\leq p\leq 10^9\)\(p\) 為質數。

分析

\[x_{i+1}\equiv ax_i+b\pmod {p}\\ x_{i+1}+\frac{b}{a}\equiv ax_{i}+b+\frac{b}{a}\pmod {p}\\ ax_{i+1}+b\equiv a^2x_{i}+ab+b\pmod {p}\\ x_{i+2}\equiv a^2x_{i}+ab+b\pmod {p} \]

  則:

\[x_2\equiv ax_1+b\pmod {p}\\ x_{3}\equiv a^2x_{1}+ab+b\pmod {p}\\ x^4\equiv a^3x_1+a^2b+ab+b\pmod p\\ \cdots\\ x_{i}\equiv a^{i-1}x_1+b(a^{i-2}+a^{i-1}+\cdots+a+1)\equiv a^{i-1}x_1+b\sum_{k=0}^{i-2}a^{k}\pmod {p} \]

  即判斷關於 \(i\) 的方程 \(t\equiv a^{i-1}x_1+b\displaystyle\sum_{k=0}^{i-2}a^{k}\pmod {p}\)

是否有整數解。

\[t\equiv a^{i-1}x_1+b\frac{1-a^{i-1}}{1-a}\pmod {p}\\ t\equiv a^{i-1}x_1+\frac{b}{1-a}-\frac{b}{1-a}·a^{i-1}\pmod {p}\\ t\equiv a^{i-1}(x_1-\frac{b}{1-a})+\frac{b}{1-a}\pmod {p}\\ a^{i-1}\equiv \frac{t-\frac{b}{1-a}}{x_1-\frac{b}{1-a}}\pmod {p} \]

  用 \(\text{BSGS}\) 演算法求解即可。

  注意:當 \(t=x_1\)

時,答案為 \(1\);當 \(a=0\) 時,\(x_i=b\);當 \(a=1\) 時,\(x_i\equiv x_1+b(i-1)\pmod {p}\),移項,\(i\equiv (t-x_1)·b^{-1}+1\pmod {p}\),求 \(i\) 即可。\(t=p\) 時要輸出 \(p\) 而不是 \(0\)

程式碼

#include<bits/stdc++.h>
using namespace std;
long long p,a,b,x1,t;
long long quick_pow(long long a,long long b,long long p)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
map<long long,long long> mp;
long long BSGS(long long a,long long b,long long p)
{
    a=a%p,b=b%p;
    long long m=sqrt(p)+1;
    long long ans=b;
    for(long long i=0;i<m;i++)
    {
        mp[ans]=i;
        ans=ans*a%p;
    }
    long long temp=quick_pow(a,m,p);
    ans=1;
    for(long long i=1;i<=m;i++)
    {
        ans=1ll*ans*temp%p;
        if(mp.count(ans))
            return i*m-mp[ans];
    }
    return -1;
}
int main()
{
    int T;
    cin>>T;
    while(T--)
    {
        mp.clear();
        scanf("%lld %lld %lld %lld %lld",&p,&a,&b,&x1,&t);
        if(t==x1)
        {
            puts("1");
            continue;
        }
        if(a==0)
        {
            if(b==t)
                puts("2");
            else
                puts("-1");
            continue;
        }
        if(a==1)
        {
            t=((t-x1)%p+p)%p;
            if(t%__gcd(b,p)!=0)
                puts("-1");
            else
            {
                if((t*quick_pow(b,p-2,p)+1)%p==0)
                    cout<<p<<endl;
                else
                    cout<<(t*quick_pow(b,p-2,p)+1)%p<<endl;
            }
            continue;
        }
        long long fz=((t-b*quick_pow(1-a,p-2,p)%p)+p)%p;
        long long fm=quick_pow(((x1-b*quick_pow(1-a,p-2,p))%p+p)%p,p-2,p);
        long long ans=BSGS(a,fz*fm%p,p);
        if(ans==-1)
            puts("-1");
        else
            cout<<ans+1<<endl;
    }
    return 0;
}