1. 程式人生 > 實用技巧 >BZOJ-2875 [Noi2012]隨機數生成器(等比數列求和)

BZOJ-2875 [Noi2012]隨機數生成器(等比數列求和)

題目描述

  給出 \(m,a,c,x_0\),按以下方式生成序列 \(\{x_i\}\)

\[x_{n+1}=(ax_n+c)\mod {m} \]

  求 \(x_n\mod g\)

  資料範圍:\(m,a,c,n,x_0\leq 10^{18},1\leq g\leq 10^8,n,m\geq 1,a,c,x_0\geq 0\)

分析

\[\begin{aligned}x_1&=a(x_0+c)\mod m\\ x_2&=(a(ax_0+c)+c)=a^2x_0+ac+c \mod m\\ x_3&=(a(ax_0+ac+c)+c)=a^3x_0+a^2c+ac+c\mod m\\ \cdots\\ x_n&=a^nx_0+c\sum_{i=0}^{n-1}a^i\mod m \end{aligned} \]

  設公比為 \(q\)\(n\) 項等比數列 \(1,q,q^2,\cdots,a^{n}\) 和為 \(S(n)\)

  若 \(n\) 為奇數:

\[\begin{aligned}&S(n)\\ =&1+q+q^2+\cdots+q^n\\ =&(1+q^{\frac{n}{2}+1})+q(1+q^{\frac{q}{2}+1})+q^2(1+q^{\frac{n}{2}+1})+\cdots +q^{\frac{n}{2}}(1+q^{\frac{n}{2}+1})\\ =&(1+q+q^2+\cdots+q^{\frac{n}{2}})(1+q^{\frac{n}{2}+1})\\ =&S(\frac{n}{2})(1+q^{\frac{n}{2}+1}) \end{aligned} \]

  若 \(n\) 為偶數:

\[\begin{aligned}&S(n)\\ =&1+q+q^2+\cdots+q^n\\ =&(1+q^{\frac{n}{2}+1})+q(1+q^{\frac{q}{2}+1})+q^2(1+q^{\frac{n}{2}+1})+\cdots +q^{\frac{n}{2}-1}(1+q^{\frac{n}{2}+1})+q^{\frac{n}{2}}\\ =&(1+q+q^2+\cdots+q^{\frac{n}{2}})(1+q^{\frac{n}{2}+1})+q^{\frac{n}{2}}\\ =&S(\frac{n}{2})(1+q^{\frac{n}{2}+1})+q^{\frac{n}{2}} \end{aligned} \]

程式碼

#include<bits/stdc++.h>
using namespace std;
long long m,a,c,x0,n,g;
long long quick_mul(long long a,long long b,long long mod)
{
    long long ans=0;
    while(b)
    {
        if(b&1)
            ans=(ans+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return ans%mod;
}
long long quick_pow(long long a,long long b,long long mod)
{
    long long ans=1;
    while(b)
    {
        if(b&1)
            ans=quick_mul(ans,a,mod)%mod;
        a=quick_mul(a,a,mod)%mod;
        b>>=1;
    }
    return ans%mod;
}
long long S(long long q,long long n)
{
    if(n==0)
        return 1;
    if(n%2==1)
        return quick_mul(S(q,n/2),1+quick_pow(q,n/2+1,m),m)%m;
    else
        return (quick_mul(S(q,n/2-1),1+quick_pow(q,n/2+1,m),m)+quick_pow(q,n/2,m))%m;
}
int main()
{
    cin>>m>>a>>c>>x0>>n>>g;
    long long ans=quick_pow(a,n,m);
    ans=quick_mul(ans,x0,m);
    ans=(ans+quick_mul(c,S(a,n-1),m))%m;
    cout<<ans%g<<endl;
    return 0;
}