参考资料:http://www.tuicool.com/articles/beiyAv
【题意】有n块砖。现要将砖全部染上红、蓝、绿、黄四种颜色。要求被染成红色和绿色的砖块数量必须为偶数,问一共有多少种染色方案。(由于答案较大,模10007)
【思路】采用dp,然后转化为矩阵。
dp:
用dp[N][4]来表示N块砖块的染色情况,一共有四种状态。
1. dp[N][0] :表示N块中红色绿色的数量均为偶数。
2. dp[N][1] :表示N块中红色为偶数,绿色为奇数。
3. dp[N][2] :表示N块中红色为奇数,绿色为偶数。
4. dp[N][3] :表示N块中红色绿色的数量均为奇数。
而状态转移方程为:
dp[N+1][0] = 2 * dp[N][0] + 1 * dp[N][1] + 1 * dp[N][2] + 0 * dp[N][3]
dp[N+1][1] = 1 * dp[N][0] + 2 * dp[N][1] + 0 * dp[N][2] + 1 * dp[N][3]
dp[N+1][2] = 1 * dp[N][0] + 0 * dp[N][1] + 2 * dp[N][2] + 1 * dp[N][3]
dp[N+1][3] = 0 * dp[N][0] + 1 * dp[N][1] + 1 * dp[N][2] + 2 * dp[N][3]
上述的转移方程可以转化为矩阵:
|2 1 1 0|
|1 2 0 1|
|1 0 2 1|
|0 1 1 2|
#include<iostream> #include<stdio.h> #include<string.h> using namespace std; const int N=5; const int mod=10007; struct Mat { int n,m; long long int mat[N][N]; void clear() { n=m=0; memset(mat,0,sizeof(mat)); } }; Mat mul(Mat a,Mat b) { Mat c; c.clear(); c.n=a.n;c.m=b.m; for(int i=0;i<=a.n;i++) { for(int k=0;k<=a.n;k++) { if(a.mat[i][k]) { for(int j=0;j<=a.n;j++) { c.mat[i][j]+=a.mat[i][k]*b.mat[k][j]; c.mat[i][j]%=mod; } } } } return c; } Mat pow(Mat a,int k) { Mat c; c.clear(); c.n=c.m=4; for(int i=0;i<4;i++) c.mat[i][i]=1; while(k) { if(k&1) c=mul(c,a); k>>=1; a=mul(a,a); } return c; } int main() { int t; scanf("%d",&t); Mat a; a.clear(); a.n=a.m=4; a.mat[0][0]=2;a.mat[0][1]=1;a.mat[0][2]=1;a.mat[0][3]=0; a.mat[1][0]=1;a.mat[1][1]=2;a.mat[1][2]=0;a.mat[1][3]=1; a.mat[2][0]=1;a.mat[2][1]=0;a.mat[2][2]=2;a.mat[2][3]=1; a.mat[3][0]=0;a.mat[3][1]=1;a.mat[3][2]=1;a.mat[3][3]=2; while(t--) { int n; scanf("%d",&n); Mat ans=pow(a,n); printf("%d ",ans.mat[0][0]); } return 0; }