题目1 : 骨牌覆盖问题·二

时间限制:10000ms
单点时限:1000ms
内存限制:256MB

描述

上一周我们研究了2xN的骨牌问题,这一周我们不妨加大一下难度,研究一下3xN的骨牌问题?
所以我们的题目是:对于3xN的棋盘,使用1x2的骨牌去覆盖一共有多少种不同的覆盖方法呢?
首先我们可以肯定,奇数长度一定是没有办法覆盖的;对于偶数长度,比如2,4,我们有下面几种覆盖方式:

输入

第1行:1个整数N。表示棋盘长度。1≤N≤100,000,000

输出

第1行:1个整数,表示覆盖方案数 MOD 12357

样例输入
62247088
样例输出
4037
以下是AC的代码
#include<cstdio>
#include<cstring>
//#define _CRT_SECURE_NO_WARNINGS
const int mod = 12357;
void matrixMultiply(int a[8][8], int b[8][8], int c[8][8]){
    int r[8][8];
    for(int i = 0; i < 8; i++){
        for(int j = 0; j < 8; j++){
            int sum = 0;
            for(int k = 0; k < 8; k++){
                sum += a[i][k] * b[k][j];
            }
            r[i][j] = sum % mod;
        }
    }
    for(int i = 0; i < 8; i++){
        for(int j = 0; j < 8; j++){
            c[i][j] = r[i][j];
        }
    }
}
int solve(int n){
    if((n & 1) == 1) return 0;
    if(n == 2) return 3;
    int M[8][8];
    memset(M, 0, sizeof(M));
    M[0][7]=M[1][6]=M[2][5]=M[3][4]=M[4][3]=M[5][2]=M[6][1]=M[7][0]=1;
    M[3][7]=M[6][7]=M[7][3]=M[7][6]=1;
    int r[8][8];
    memset(r, 0, sizeof(r));
    //printf("%d\n", sizeof(r));
    r[0][0]=r[1][1]=r[2][2]=r[3][3]=r[4][4]=r[5][5]=r[6][6]=r[7][7]=1;
    while(n > 1){
        if(n & 1) matrixMultiply(r, M, r);
        matrixMultiply(M, M, M);
        n >>= 1;
    }
    matrixMultiply(r, M, r);
    return r[7][7];
}
int main(){
    int n;
    scanf("%d", &n);
    printf("%d\n", solve(n));
    return 0;
}