poj3734

题意:给n个block涂4种颜色,要求其中red和green的block为偶数,其余随意。问有多少种涂法。

分析:这题我们可以先认为是一道dp题,设f[maxn][4],f[i][j]表示有i个block时,green和red的奇偶性为状态j时(及把j化为二进制第一位表示green是否为奇数,第二位对应red)。则我们可以由f[i - 1]推出f[i]。递推的过程是将f[i-1]的各位进行一些加法运算并附给f[i]的对应位。这个过程我们可以用矩阵来解决。f[i-1]是一个1*4的矩阵,乘以一个4*4的矩阵之后得到一个1*4的矩阵即为f[i]。线代的知识这里就不说了。本题f[0]={1,0,0,0}; 4*4矩阵={{2,1,1,0},{1,2,0,1},{1,0,2,1},{0,1,1,2}};

化为矩阵后有个好处就是可以用快速幂把n次运算改为logn次运算。

View Code
#include <iostream>
#include
<cstdio>
#include
<cstdlib>
#include
<cstring>
usingnamespace std;

#define maxn 4
#define w 10007

struct Matrix
{
int a[maxn][maxn];
int x, y;
}ans, f;

int n;
int matrix[maxn][maxn]={{2,1,1,0},{1,2,0,1},{1,0,2,1},{0,1,1,2}};

Matrix mul(Matrix
&a, const Matrix &b)
{
Matrix ret;
for (int i =0; i < a.x; i++)
for (int j =0; j < b.y; j++)
{
int d =0;
for (int k =0; k < a.y; k++)
d
= (d + a.a[i][k] * b.a[k][j] % w) % w;
ret.a[i][j]
= d;
}
ret.x
= a.x;
ret.y
= b.y;
return ret;
}

Matrix power(Matrix m,
int n)
{
Matrix ret;
memset(ret.a,
0, sizeof(ret.a));
for (int i =0; i <4; i++)
ret.a[i][i]
=1;
ret.x
= ret.y =4;
for (int k =1; k <= n; k <<=1)
{
if (k & n)
ret
= mul(ret, m);
m
= mul(m, m);
}
return ret;
}

int main()
{
#ifndef ONLINE_JUDGE
freopen(
"t.txt", "r", stdin);
#endif
f.x
= f.y =4;
for (int i =0; i <4; i++)
for (int j =0; j <4; j++)
f.a[i][j]
= matrix[i][j];
int t;
scanf(
"%d", &t);
while (t--)
{
scanf(
"%d", &n);
f.x
= f.y =4;
memset(ans.a,
0, sizeof(ans.a));
ans.a[
0][0] =1;
ans.x
=1;
ans.y
=4;
ans
= mul(ans, power(f, n));
printf(
"%d\n", ans.a[0][0]);
}
return0;
}
原文地址:https://www.cnblogs.com/rainydays/p/2109702.html