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;
}

毕竟不是正解(NOI试试)

正经点,写了个高精度乘法,然后一位一位乘过去,边乘边取模,用了\(unsigned \quad long \quad long\)

#include<cstdio>
#include<iostream>
#include<cstring>
#define n 2
#define ll long long
using namespace std;
ll m,a,c,X0,N,g;
int xw,yw,xx[25],yy[25],w[45];
ll cf(ll x,ll y)//高精度
{
    if (!x||!y)
        return 0;
    xw=0,yw=0;
    while (x)
    {
        xw++;
        xx[xw]=x%10;
        x/=10;
    }
    while (y)
    {
        yw++;
        yy[yw]=y%10;
        y/=10;
    }
    memset(w,0,sizeof w);
    for (int i=1;i<=xw;i++)
        for (int j=1;j<=yw;j++)
            w[i+j-1]+=xx[i]*yy[j];
    for (int i=1;i<=42;i++)
        if (w[i]>9)
        {
            w[i+1]+=w[i]/10;
            w[i]%=10;
        }
    int len=0;
    for (int i=42;i>=1;i--)
        if (w[i])
        {
            len=i;
            break;
        }
    unsigned long long ans=0;
    for (int i=len;i>=1;i--)
        ans=(ans*10+w[i])%m;
    return ans;
}
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]+cf(f[i][k],b.f[k][j]))%m;
        return c;
    }
}zero,ans,cs,zy;
ll read()
{
    ll 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(ll 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;
}

还可以用龟速乘处理

#include<cstdio>
#include<iostream>
#define n 2
#define ll long long
using namespace std;
ll m,a,c,X0,N,g;
ll cf(ll x,ll y)//龟速乘
{
    ll ans=0;
    while (y)
    {
        if (y&1)
            ans=(ans+x)%m;
        x=(x << 1)%m;
        y >>=1;
    }
    return ans;
}
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]+cf(f[i][k],b.f[k][j]))%m;
        return c;
    }
}zero,ans,cs,zy;
ll read()
{
    ll 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(ll 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;
}

实测还是高精度最快

posted @ 2020-07-26 19:29  GK0328  阅读(101)  评论(0编辑  收藏  举报