1. 程式人生 > >POJ3734Blocks(遞推+矩陣快速冪)

POJ3734Blocks(遞推+矩陣快速冪)

ace pro view display \n 方塊 namespace 圖片 個數

題目鏈接:http://poj.org/problem?id=3734

題意:給出n個排成一列的方塊,用紅、藍、綠、黃四種顏色給它們染色,求染成紅、綠的方塊個數同時為偶數的方案數模10007的值。

題解:這是WC2019第二課堂生成函數的題,實際上可以不用生成函數,我們考慮如下狀態:a[i]表示前i個中紅、綠均為偶的方案數,b[i]表示其中一個為奇數的方案數,c[i]表示都為奇數的方案數。然後可以這樣轉移:a[i]=2a[i-1]+b[i-1],b[i]=2a[i-1]+2b[i-1]+2c[i-1],c[i]=2c[i-1]+b[i-1],由於n<=1e9,所以用矩陣優化即可,復雜度O(27qlogn)

備註:由於POJ編譯器太垃圾,矩陣乘法傳輸數組會CE,所以代碼很長。

技術分享圖片
#include<cstdio>
#include<algorithm>
using namespace std;
const int mod=10007;
int n,a[4][4],ret[4][4],c[4][4];
int main()
{
    int T;scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&n);
        for(int i=0;i<3;i++)
        for(int j=0
;j<3;j++) ret[i][j]=(i==j); a[0][0]=2,a[0][1]=1,a[0][2]=0; a[1][0]=2,a[1][1]=2,a[1][2]=2; a[2][0]=0,a[2][1]=1,a[2][2]=2; while(n) { if(n&1) { for(int i=0;i<3;i++) for(int j=0;j<3;j++) { c[i][j]
=0; for(int k=0;k<3;k++)c[i][j]=(c[i][j]+ret[i][k]*a[k][j])%mod; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) ret[i][j]=c[i][j]; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) { c[i][j]=0; for(int k=0;k<3;k++)c[i][j]=(c[i][j]+a[i][k]*a[k][j])%mod; } for(int i=0;i<3;i++) for(int j=0;j<3;j++) a[i][j]=c[i][j]; n>>=1; } printf("%d\n",ret[0][0]); } }
View Code

POJ3734Blocks(遞推+矩陣快速冪)