HNOI2011 数学作业

Posted zcdhj

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HNOI2011 数学作业相关的知识,希望对你有一定的参考价值。

Luogu

裸的矩阵快速幂。

\(S_i\)表示\(Concatenate(1...i)\)的值,\(f(i)\)为数字\(i\)的位数,得到递推式\(S_i=S_{i-1}*10^i+i\)

设状态矩阵为
\[ \begin{bmatrix} S_{i-1}\quad i \quad 1 \end{bmatrix} \]
其中\(1\)是为了方便\(i\)\(1\)

转移矩阵为
\[ \begin {bmatrix} 10^{f(i)} \quad 0 \quad 0\ 1 \qquad 1 \qquad 0 \ 0 \qquad 1 \qquad 1 \\end {bmatrix} \]
我们发现,这个\(f(i)\)会变化,无法进行矩阵快速幂。然而\(N≤10^{18}\)也就是说\(f(i)\)最多会变化\(18\)次,接下来只需要暴力分段枚举\(10^{f(i)}\)就可以了。

#include <cstdio>
#include <cstring>

typedef long long ll;

struct Matrix
{
    ll matrix[3][3];
    Matrix()
    {
        memset(matrix,0,sizeof(matrix));
    }
    void clear()
    {
        memset(matrix,0,sizeof(matrix));
    }
}S,T;

ll N,M;

Matrix mul(Matrix x,Matrix y)
{
    Matrix s;
    for(int i=0;i<3;++i)
        for(int j=0;j<3;++j)
            for(int k=0;k<3;++k)
                (s.matrix[i][j]+=(x.matrix[i][k]*y.matrix[k][j])%M)%=M;
    return s;
}

Matrix fst_pow(Matrix a,ll x)
{
    Matrix r=a,base=a;
    for(x=x-1;x;x>>=1)
    {
        if(x&1) r=mul(r,base);
        base=mul(base,base);
    }
    return r;
}

int main()
{
    ll t,x; 
    scanf("%lld %lld",&N,&M);
    t=N;
    S.matrix[0][1]=S.matrix[0][2]=1;
    for(ll i=10;t;i*=10)
    {
        if(N>=i) x=i-i/10;
        else x=t;
        t-=x;
        T.clear();
        T.matrix[1][0]=T.matrix[1][1]=T.matrix[2][1]=T.matrix[2][2]=1,T.matrix[0][0]=i%M;
        S=mul(S,fst_pow(T,x));
    }
    printf("%lld",S.matrix[0][0]);
    return 0;
}

以上是关于HNOI2011 数学作业的主要内容,如果未能解决你的问题,请参考以下文章

bzoj2326: [HNOI2011]数学作业

洛谷P3216 [HNOI2011]数学作业

[luogu P3216] [HNOI2011]数学作业

[HNOI2011]数学作业

[HNOI2011]数学作业

BZOJ2326[HNOI2011]数学作业 矩阵乘法