XDU 1111

对于一排n个正方形,有f(n)种方案达成目标,若第n个块是白色,则有f(n-1)种方案,若第n个块是黑色,则第n-1个块必为白色,那么有f(n-2)+n-2种方案。 
则f(n)=f(n-1)+f(n-2)+n-2 。 
写成矩阵形式: 
(http://img.blog.csdn.net/20161011211956406
例如:(i,j)表示i个空涂j个的种类数 
(9,2)=(7,1)+(6,1)+(5,1)+(4,1)+(3,1)+(2,1)+(1,1) 
(9,3)=(7,2)+(6,2)+(5,2)+(4,2)+(3,2) 
(9,4)=(7,3)+(6,3)+(5,3) 
(9,5)=(7,4) 
(8,2)=(6,1)+(5,1)+(4,1)+(3,1)+(2,1)+(1,1) 
(8,3)=(6,2)+(5,2)+(4,2)+(3,2) 
(8,4)=(6,3)+(5,3)

#include<cstdio>
#include<cstring>
typedef long long ll;
const ll mod=1e9+7;
struct Mat
{
    ll mat[4][4];
};
Mat Mult(Mat a,Mat b)
{
    Mat c;
    memset(c.mat,0,sizeof(c.mat));
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            for(int k=0;k<4;k++)
                c.mat[i][j]=(c.mat[i][j]+a.mat[i][k]*b.mat[k][j])%mod;
    return c;
}

Mat QMult(Mat a,ll b)
{
    Mat c;
    for(int i=0;i<4;i++)
        for(int j=0;j<4;j++)
            c.mat[i][j]=i==j;
    while(b){
        if(b&1)
            c=Mult(c,a);
        a=Mult(a,a);
        b>>=1;
    }
    return c;
}

int main()
{
    ll n;
    while(~scanf("%lld",&n))
    {
        Mat res;
        if(n==2)
        {
            puts("0");
            continue;
        }
        else if(n==3)
        {
            puts("1");
            continue;
        }
        memset(res.mat,0,sizeof(res.mat));
        res.mat[0][0]=res.mat[0][1]=res.mat[0][2]=res.mat[1][0]=1;
        res.mat[2][2]=res.mat[2][3]=res.mat[3][3]=1;
        res=QMult(res,n-3);
        printf("%lld
",(res.mat[0][0]+2*res.mat[0][2]+res.mat[0][3])%mod);
    }
    return 0;
 } 
原文地址:https://www.cnblogs.com/freinds/p/6292118.html