BZOJ2326 HNOI2011 数学作业 矩阵乘法

题意:求12345……101112……(N-1)N mod M的值(被模数就是1-N顺次连接起来)。

题解:丧病的数学老师,看自己写的题解都看不懂了QAQ,首先设${f_i}$=前i个数连接起来 mod M的值,然后按位数不断转移,也就是说,假定当前要增加的数i最高位是10^k,那么\[{f_i} = ({10^{k + 1}}{f_{i - 1}} + i)\bmod M\]

所以\[\left( {\begin{array}{*{20}{c}}
{{f_{{{10}^{k + 1}} - 1}}}&{{{10}^{k + 1}} - 1}&1
\end{array}} \right) = \left( {\begin{array}{*{20}{c}}
{{f_i}}&{{{10}^{k - 1}}}&1
\end{array}} \right){\left( {\begin{array}{*{20}{c}}
{{{10}^k}}&0&0\\
1&1&0\\
1&1&1
\end{array}} \right)^{{{10}^k} - 2}}\]

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <climits>
#include <iostream>
#include <algorithm>
using namespace std;
#define ll long long

const int MAXN=4+2;
ll N,M,a[MAXN][MAXN],b[MAXN][MAXN];

ll Quick_Mul(ll a,ll b){
    a%=M,b%=M;
    ll t=(b&1?a:0);

    while(b>>=1){
        a=(a+a)%M;
        if(b&1) t=(t+a)%M;
    }

    return t;
}

void Matrix_Mul(bool f){
    ll t[MAXN][MAXN];
    memset(t,0,sizeof(t));

    if(!f){
        for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            for(int k=1;k<=3;k++)
                t[i][j]=(t[i][j]+Quick_Mul(a[i][k],b[k][j]))%M;
        }
        memcpy(a,t,sizeof(a));
    }

    else{
        for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
            for(int k=1;k<=3;k++)
                t[i][j]=(t[i][j]+Quick_Mul(b[i][k],b[k][j]))%M;
        }
        memcpy(b,t,sizeof(b));
    }
}

void Quick_Pow(ll x,ll y){
    memset(b,0,sizeof(b));
    b[1][1]=x,b[2][1]=b[2][2]=b[3][1]=b[3][2]=b[3][3]=1;

    ll t=y-x/10+1;
    while(t){
        if(t&1) Matrix_Mul(0);
        Matrix_Mul(1);
        t>>=1;
    }
}

int main(){
    scanf("%lld %lld",&N,&M);

    a[1][1]=a[2][2]=a[3][3]=1;
    ll t=10;
    while(N>=t) Quick_Pow(t,t-1),t*=10;
    Quick_Pow(t,N);

    printf("%lld",a[3][1]);

    return 0;
}
View Code

 

posted @ 2017-02-26 11:21  WDZRMPCBIT  阅读(137)  评论(0编辑  收藏  举报