poj3734 Blocks

传送门

题目大意

有n个方块,有1,2,3,4四种颜色对其进行染色,求1,2颜色的方块个数均为偶数的方案数对10007取模的值。

分析

我们假设1表示这个颜色个数是奇数,0表示是偶数,所以对于所有状态我们可以分为四种,每种对应一个二元组 ,二元组的第一项表示颜色1,第二项表示颜色2,这四种分别是(1,1),(1,0),(0,1),(0,0)。但是我们不难发现(1,0)和(0,1)这两种状态可以合为一种,所以我们可以推出:

(1,1) = 2*(1,1) + (1,0)

(1,0) = (1,1) + 2*(1,0) + 2*(0,0)

(0,0) = 2*(0,0) + (1,0)

我们通过这个便可以得到转移矩阵了。详见代码。

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<ctime>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
const int mod = 10007;
struct mat {
      int g[5][5];
};
inline mat operator * (mat a,mat b){
      mat c;
      for(int i=1;i<=3;i++)
        for(int j=1;j<=3;j++){
          int x=0;
          for(int k=1;k<=3;k++)
            x=(x+a.g[i][k]*b.g[k][j]%mod)%mod;
          c.g[i][j]=x;
        }
      return c;
}
inline int pw(int p){
      mat res,a;
      a.g[1][1]=a.g[2][1]=a.g[2][2]=a.g[2][3]=a.g[3][3]=2;
      a.g[1][2]=a.g[3][2]=1;
      a.g[1][3]=a.g[3][1]=0;
      res=a;
      while(p){
          if(p&1)res=res*a;
          a=a*a;
          p>>=1;
      }
      return res.g[3][3];
} 
int main(){
      int n,t;
      scanf("%d",&t);
      while(t--){
        scanf("%d",&n);
        printf("%d
",pw(n-1)); 
      }
      return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/9463959.html