【题意】
给N个方块排成一列。现在要用红、蓝、绿、黄四种颜色的油漆给这些方块染色。求染成红色方块和染成绿色方块的个数同时为偶数的染色方案的个数,输出对10007取余后的答案。(1<=n<=10^9)。
【分析】
看到这题的题目的第一想法是什么呢?我也不知道,因为还没做就知道是一道用矩阵乘法完成递推的题目了嘛!!
之前对矩阵乘法的理解不是很好,不知道可以同时推很多个元素的,于是脑子就卡了~~不写那么多乱七八糟的想法了,直接写题解吧。
当我们准备准备染第i个方块的时候,前i-1个方块已经染好颜色了。对于我们的目标颜色红色和绿色,根据我们想要红绿同时为偶的想法,我们可以把前i-1个方块的染色分成3种情况:
1.红色和绿色同时为偶数的方案数
2.红色和绿色中一个偶数一个奇数的方案数
3.红色和绿色同时为奇数的方案数
我们记前3种情况的方案数为ai-1,bi-1,ci-1。
我们最后需要的是an,但是我们需要a,b,c进行递推。
根据以上想法,我们希望用ai-1,bi-1,ci-1推出ai,bi,ci。
那么,多一个格子染色方案有多少个,是很容易推出来的哦:
ai=2*ai-1+bi-1;
bi=2*ai-1+2*bi-1+2*ci-1;
ci=bi-1+2*c-1;
根据这个递推式,我们可以得到矩阵A:
2 | 1 | 0 |
2 | 2 | 2 |
0 | 1 | 2 |
矩阵B为i=0的时候a,b,c的值:
1 |
0 |
0 |
然后用同样的快速幂求矩阵乘法的方法求解。
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #define Mod 10007 5 6 struct node 7 { 8 int v[5][5]; 9 int m,l; 10 }; 11 12 node get_mul(node a,node b) 13 { 14 node c; 15 c.m=a.m;c.l=b.l; 16 for(int i=1;i<=c.m;i++) 17 for(int j=1;j<=c.l;j++) 18 { 19 c.v[i][j]=0; 20 for(int k=1;k<=a.l;k++) 21 c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%Mod; 22 } 23 return c; 24 } 25 26 int main() 27 { 28 int T,n; 29 scanf("%d",&T); 30 while(T--) 31 { 32 scanf("%d",&n); 33 node a,b,c; 34 a.m=a.l=3;a.v[1][1]=2;a.v[1][2]=1;a.v[1][3]=0; 35 a.v[2][1]=a.v[2][2]=a.v[2][3]=2; 36 a.v[3][1]=0,a.v[3][2]=1,a.v[3][3]=2; 37 b.m=3,b.l=1,b.v[1][1]=1,b.v[2][1]=0,b.v[3][1]=0; 38 c.m=c.l=3;c.v[1][1]=c.v[2][2]=c.v[3][3]=1; 39 c.v[1][2]=c.v[1][3]=c.v[2][1]=c.v[2][3]=c.v[3][1]=c.v[3][2]=0; 40 while(n) 41 { 42 if(n&1) c=get_mul(c,a); 43 a=get_mul(a,a); 44 n>>=1; 45 } 46 c=get_mul(c,b); 47 printf("%d\n",c.v[1][1]); 48 } 49 return 0; 50 }
poj3734
有人能教我如何漂亮地打表么?
2015-09-19 10:57:49
时间: 2024-11-03 14:38:22