1. 程式人生 > 實用技巧 >Luogu2044 [NOI2012]隨機數生成器

Luogu2044 [NOI2012]隨機數生成器

https://www.luogu.com.cn/problem/P2044

矩陣快速冪

\[X_{n+1}=aX_{n}+c\\ \begin{cases} X_{n+1}=aX_{n}+1*c\\ c=0*X_{n}+1*c \end{cases} \]

但是模數有點大(\(10^{18}\)),會爆\(long\quad long\)

雖然可以__int128跑過去

#include<cstdio>
#include<iostream>
#define n 2
#define ll __int128
using namespace std;
ll m,a,c,X0,N,g;
struct mat
{
    ll f[n+1][n+1];
    mat operator *(mat b)
    {
        mat c;
        for (int i=1;i<=n;i++)
            for (int j=1;j<=n;j++)
                c.f[i][j]=0;
        for (int k=1;k<=n;k++)
            for (int i=1;i<=n;i++)
                for (int j=1;j<=n;j++)
                    c.f[i][j]=(c.f[i][j]+f[i][k]*b.f[k][j])%m;
        return c;
    }
}zero,ans,cs,zy;
__int128 read()
{
    __int128 s=0;
    char c=getchar();
    while (!isdigit(c))
        c=getchar();
    while (isdigit(c))
    {
        s=(s << 3)+(s << 1)+(c^48);
        c=getchar();
    }
    return s;
}
void write(__int128 x)
{
    if (x>=10)
        write(x/10);
    putchar(x%10+48);
}
mat ksm(mat x,ll y)
{
    mat ans=zero;
    while (y)
    {
        if (y&1)
            ans=ans*x;
        x=x*x;
        y >>=1;
    }
    return ans;
}
int main()
{
    for (int i=1;i<=n;i++)
        zero.f[i][i]=1;
    m=read(),a=read(),c=read(),X0=read(),N=read(),g=read();
    cs.f[1][1]=X0,cs.f[2][1]=c;
    zy.f[1][1]=a,zy.f[1][2]=1,zy.f[2][2]=1;
    ans=ksm(zy,N)*cs;
    write(ans.f[1][1]%g),putchar('\n');
    return 0;
}