Blocks [POJ3734] [矩阵快速幂]

题意:

有长度为n的一排格子,每个格子里面可以任意填入1,2,3,4四个数字,问1,2都为偶数个的方案

T组数据,每组数据一个n(<=1e9)

样例输入

2

1

2

样例输出

2

6

分析

设dp[i][0/1/2/3]分别为处理到第i个,1和2的个数分别为 全偶、1偶2奇、1奇2偶,全奇

那么dp转移方程为

dp[i][0]=2dp[i-1][0]+dp[i-1][1]+dp[i-1][2] 填的分别是 3/4 1 2

dp[i][1]=dp[i-1][0]+2dp[i-1][1]+dp[i-1][3] 填的分别是 2 3/4 1

dp[i][2]=dp[i-1][0]+2dp[i-1][2]+dp[i-1][3] 填的分别是 1 3/4 2

dp[i][3]=dp[i-1][1]+dp[i-1][2]+2dp[i-1][3] 填的分别是 1 2 3/4

我们发现dp[i][1]和dp[i][2]可以合并在一起

那么将dp[i][1]和dp[i][2]合并为dp[i][1],dp[i][3]改为dp[i][2]

那么dp转移方程简化为:(简化方式为上面2式和3式相加,dp[i][1]和dp[i][2]替换为dp[i][1],dp[i][3]替换为dp[i][2])

dp[i][0]=2dp[i-1][0]+dp[i-1][1]

dp[i][1]=2dp[i-1][0]+2dp[i-1][1]+2dp[i-1][3]

dp[i][2]=dp[i-1][1]+2dp[i-1][2]

我们发现n=1e9直接推会T,所以就上矩阵快速幂,初始矩阵为

| 2 2 0 |

| 0 0 0 |

| 0 0 0 |

转置矩阵为

| 2 2 0 |

| 1 2 1 |

| 0 2 2 |

代码 

 1 #include<set>
 2 #include<map>
 3 #include<queue>
 4 #include<stack>
 5 #include<cmath>
 6 #include<cstdio>
 7 #include<cstring>
 8 #include<iostream>
 9 #include<algorithm>
10 #define RG register int
11 #define rep(i,a,b)    for(RG i=a;i<=b;++i)
12 #define per(i,a,b)    for(RG i=a;i>=b;--i)
13 #define ll long long
14 #define inf (1<<29)
15 using namespace std;
16 ll T,n;
17 const ll mo=10007;
18 inline int read()
19 {
20     int x=0,f=1;char c=getchar();
21     while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
22     while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
23     return x*f;
24 }
25 
26 struct Mat{
27     ll a[3][3];
28     Mat(){memset(a,0,sizeof(a));}
29     inline ll * operator [] (const int x){return a[x];}
30     inline Mat operator *(Mat b)
31     {
32         Mat ans;
33         rep(i,0,2)    rep(j,0,2)    rep(k,0,2)
34             (ans[i][j]+=(a[i][k]*b[k][j]))%=mo;
35         return ans;
36     }
37 };
38 
39 void work()
40 {
41     Mat S,T;
42     S[0][0]=2,S[0][1]=2,S[0][2]=0,
43     T[0][0]=2,T[0][1]=2,
44     T[1][0]=1,T[1][1]=2,T[1][2]=1,
45               T[2][1]=2,T[2][2]=2;
46     while(n)
47     {
48         if(n&1)S=S*T;
49         T=T*T;
50         n>>=1;
51     }
52     printf("%lld\n",S[0][0]);
53 }
54 
55 int main()
56 {
57     T=read();
58     while(T--)
59     {
60         n=read();
61         work();
62     }
63     return 0;
64 }
View Code

 

posted @ 2018-07-15 19:33  iBilllee  阅读(147)  评论(0编辑  收藏  举报