HRBUST 2372 小L的问题

Problem

小L是一个可爱的女孩,她特别喜欢玩多米诺骨牌。有一天她得到了一个宽度为2长度为n的棋盘。她现在有1*2大小的矩形骨牌和3格大小的L型骨牌(L型骨牌的样式参考Hint)。她发现有很多种方式可以让这个棋盘完全覆盖,她想知道对于每一个2*n大小的棋盘,用这两种骨牌完全覆盖的方案数。这个数字可能很大,所以答案需要模1000000007.

Input

输入数据第一行为T,代表数据组数。

接下来的T行中,每一行只有一个数字n,n为不超过1e18的正整数,代表棋盘的长度。

Output

输出T行,每行为对应n的答案。 

Sample Input

1

2 

Sample Output

2 

Code

#include <cstdio>
#define ll long long
const int MOD = 1000000007;
const int N = 3;
struct Matrix {
    ll mat[N][N];
    Matrix operator*(const Matrix& m)const {
        Matrix tmp;
        for (ll i = 0 ; i < N ; i++) {
            for (ll j = 0 ; j < N ; j++) {
                tmp.mat[i][j] = 0;
                for (ll k = 0 ; k < N ; k++)
                    tmp.mat[i][j] = (tmp.mat[i][j] + mat[i][k]*m.mat[k][j])%MOD;
                tmp.mat[i][j] %= MOD;
            }
        }
        return tmp;
    }
};
Matrix m;
int T;
ll n;
ll Pow(ll n) {
    n-=2;
    Matrix k,ans,e;
    k.mat[0][0]=1; k.mat[0][1]=1; k.mat[0][2]=2;//f[i]=f[i-1]+f[i-2]+2*g[i-3]
    k.mat[1][0]=1; k.mat[1][1]=0; k.mat[1][2]=0;//f[i-1]=f[i-1]
    k.mat[2][0]=0; k.mat[2][1]=1; k.mat[2][2]=1;//g[i-2]=f[i-2]+g[i-3]
    for (int i=0;i<N;++i) for (int j=0;j<N;++j) ans.mat[i][j]=e.mat[i][j]=0;
    ans.mat[0][0]=2;//f2=2
    ans.mat[1][0]=1;//f1=1
    ans.mat[2][0]=1;//g0=1
    for (int i=0;i<N;++i) e.mat[i][i]=1;
    while (n) {
        if (n&1) e = e*k;
        k=k*k;
        n>>=1;
    }
    ans=e*ans;
    return ans.mat[0][0]%MOD;
}
int main() {
    scanf("%d",&T);
    while (T--) {
        scanf("%lld",&n);
        if (n==0) printf("1\n");
        else if (n==1) printf("1\n");
        else if (n==2) printf("2\n");
        else printf("%lld\n",Pow(n));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ACM2017/article/details/79696600