bzoj2326: [HNOI2011]数学作业

矩阵乘法.

                                      10^k,0,0

(f[i+1],i+1,1) = (f[i],i,1)  ( 1,     1,0 )

                                       1.     1,0)

k为(i+1)的位数。这点很重要,所以每回都是算到999…9,然后k就会+1。所以题目中的l和r都是实际值+1。(需要yy一下)。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
unsigned long long n,mod;

struct Matrix {
    long long a[3][3];
    
    long long* operator [] (int x) {
        return a[x];
    }
    
    Matrix operator* (Matrix b) {
        Matrix res;
        for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
        for(int k=0;k<3;k++)
        res[i][j]=(res[i][j]+a[i][k]*b[k][j])%mod;
        return res;    
    }
    
    Matrix operator ^ (long long e) {
        Matrix res(1),tmp=*this;
        while(e) {
            if(e&1) res=res*tmp;
            tmp=tmp*tmp;
            e>>=1;
        }
        return res;
    }
    
    void build(long long x) {
        memset(a,0,sizeof(a));
        a[0][0]=x%mod;
        for(int i=1;i<3;i++)
        for(int j=0;j<=i;j++)
            a[i][j]=1;
    }
    
    Matrix(long long x=0) {
        memset(a,0,sizeof(a));
        for(int i=0;i<3;i++) a[i][i]=x;    
    }
    
}cur;

struct Vector {
    long long a[3];    
    
    long long& operator [] (int x) {
        return a[x];
    }
    
    Vector operator * (Matrix b) {
        Vector res;
        for(int i=0;i<3;i++) 
        for(int k=0;k<3;k++) 
            res[i]=(res[i]+a[k]*b[k][i])%mod;
        return res;
    }
    
    void build() {
        memset(a,0,sizeof(a));    
        a[2]=1;
    }
    
    Vector() {
        memset(a,0,sizeof(a));
    }
}res;

int main() {
    scanf("%lld%lld",&n,&mod);
    res.build();
    long long l,r;
    for(l=1,r=10;r<=n;l=r,r=l*10) {
        cur.build(r);
        res=res*(cur^(r-l));
    }
    cur.build(r);
    res=res*(cur^(n-l+1));
    printf("%lld\n",res[0]);
    return 0;
}
posted @ 2016-05-25 10:20  invoid  阅读(128)  评论(0编辑  收藏  举报