码迷,mamicode.com
首页 > 其他好文 > 详细

HNOI2011 数学作业

时间:2018-02-09 23:52:03      阅读:206      评论:0      收藏:0      [点我收藏+]

标签:begin   cat   +=   string   math   ref   矩阵快速幂   就是   display   

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 数学作业

标签:begin   cat   +=   string   math   ref   矩阵快速幂   就是   display   

原文地址:https://www.cnblogs.com/zcdhj/p/8436937.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!