Input
The first line of the input contains an integer T(1≤T≤100), the number of test cases. Each of the next T lines contains an integer N(1≤N≤10^9) indicating the number of blocks.
Output
For each test cases, output the number of ways to paint the blocks in a single line. Since the answer may be quite large, you have to module it by 10007.
Sample Input
2
1
2
Sample Output
2
6
思路:
假设从左边开始染色。设染到第i个时,红绿都是偶数的方案数为a(i),红绿恰有一个是偶数的方案数为b(i),红绿都为奇数的方案数为c(i),那么染到第i+1个方块时,红绿都为偶数的方案只有两种可能
1:染到第i 个后,红绿的数量都为偶数,第i+1 个方块染成黄色或者蓝色;
2:染到第i 个后,红绿数量恰有一个偶数,第i+1 个方块染成红绿中数量是奇数的那种颜色
因此得到递推公式:a(i+1)=2*a(i)+b(i),
同样的递推,能得到:
b(i+1)=2*a(i)+2*b(i)+2*c(i)
c(i+1)=b(i)+2*c(i)
使用矩阵来表示此递推式可得:
| a(i+1) | | 2 1 0 | | a(i) |
| b(i+1) | = | 2 2 2 | * | b(i) |
| c(i+1) | | 0 1 2 | | c(i) |
然后n个矩阵乘积的运算用到二进制优化
AC代码:
#include<stdio.h>
#include<string.h>
const int mod=10007;
struct matrix
{
int mat[3][3];
matrix friend operator *(matrix a,matrix b){
matrix tmp;
memset(tmp.mat,0,sizeof(tmp.mat));
for(int i=0;i<3;++i){
for(int j=0;j<3;++j){
if(!a.mat[i][j])
continue;
for(int k=0;k<3;++k){
tmp.mat[i][k]+=(a.mat[i][j]*b.mat[j][k])%mod;
tmp.mat[i][k]%=mod;
}
}
}
return tmp;
}
};
int slove(int n){
matrix base={2,1,0,2,2,2,0,1,2},ans={0};
for(int i=0;i<3;++i)
ans.mat[i][i]=1;
while(n){
if(n&1)
ans=ans*base;
base=base*base;
n>>=1;
}
return ans.mat[0][0];
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
printf("%d\n",slove(n));
}
return 0;
}
1982

被折叠的 条评论
为什么被折叠?



