poj 3734 Blocks 矩阵乘法优化dp

来源:互联网 发布:cacti不出数据 编辑:程序博客网 时间:2024/04/30 04:48

Description

Panda has received an assignment of painting a line of blocks. Since Panda is such an intelligent boy, he starts to think of a math problem of painting. Suppose there are N blocks in a line and each block can be paint red, blue, green or yellow. For some myterious reasons, Panda want both the number of red blocks and green blocks to be even numbers. Under such conditions, Panda wants to know the number of different ways to paint these blocks.

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



传送门
题意:n个格子,每个位置可以填颜色1~4,其中1和2颜色数目都要偶数个,
问有几种方案。


首先很容易发现,具体的数目没有用处,
只用关心那两种颜色的奇偶性。
可以用F[i][j][k]表示前i位,第1种颜色奇偶性为j(0/1),第2种是k,
那么递推式很简单,不赘述。
但是n很大,这个O(n)的算法是不行的。
但是发现F[i]只和F[i-1]有关,所以可以考虑考虑矩阵优化。


为了书写方便,我们把式子变成:
a[i]:前i个,都是偶数的方案数
b[i]:前i个,有1个奇数的方案数
c[i]:前i个,都是奇数的方案数
那么转移仍然很简单,表示一下:
a[i]=b[i1]+2a[i1]
b[i]=2a[i1]+2b[i1]+2c[i1]
c[i]=b[i1]+2c[i1]
也就是每次选中哪个的关系了(自己推推)


那么这个转移看上去就很有矩阵的潜质(雾。。)
显然我们需要的是a[i],b[i],c[i],那就考虑从i-1项推到i项,
……很简单的推导啊这题。。。= =推出来是这样子的:

220121022

然后加个快速幂就好啦= v =

#include<cstdio>#include<cstring>using namespace std;const int    mod=10007;int a[4][4],z[4][4],c[4][4],e[4][4];void cheng(int a[4][4],int b[4][4]){    for (int i=1;i<=3;i++)        for (int j=1;j<=3;j++){            c[i][j]=0;            for (int k=1;k<=3;k++)                (c[i][j]+=a[i][k]*b[k][j]%mod)%=mod;        }}void ksm(int n){    memset(z,0,sizeof(z));    for (int i=1;i<=3;i++) z[i][i]=1;    memcpy(e,a,sizeof(e));    while (n){        if (n&1){            cheng(e,z);            memcpy(z,c,sizeof(z));        }        n>>=1;        cheng(e,e);        memcpy(e,c,sizeof(e));    }}int main(){    int n,cas;scanf("%d",&cas);    a[1][1]=2,a[1][2]=1,a[1][3]=0;    a[2][1]=a[2][2]=a[2][3]=2;    a[3][1]=0,a[3][2]=1,a[3][3]=2;    while (cas--){        scanf("%d",&n);        ksm(n);        printf("%d\n",z[1][1]);    }    return 0;}