您的位置:首页 > 其它

POJ-3734(DP + 矩阵求幂)

2015-03-05 19:22 183 查看
题目:http://poj.org/problem?id=3734

刚开始看到题目N<10^9吓蒙了都,看了discuss才明白,还是对DP理解的太浅呢。。。

分析:我们更多的关心红色和绿色的情况,限制条件是两者个数都是偶数,但子问题却可能出现两者一奇一偶、一偶一奇、两奇的情况,假设已经给n个块染色,且出现这4种情况的场面分别有{a, b, c, d}个,给第n+1个块染色之后可能构成的场面和数量分别为{m, n, p, q},我们来看两者是不是有一定的关系:

1、如果给第n+1个块染红色,则两偶 -> 一奇一偶;一奇一偶 -> 两偶;一偶一奇 -> 两奇;两奇 -> 一偶一奇。

2、如果给第n+1个块染绿色,则两偶 -> 一偶一奇;一奇一偶 -> 两奇;一偶一奇 -> 两偶;两奇 -> 一奇一偶。

3、如果给第n+1个块染黄色,则两偶 -> 两偶;一奇一偶 -> 一奇一偶;一偶一奇 -> 一偶一奇;两奇 -> 两奇。

4、如果给第n+1个块染蓝色,则两偶 -> 两偶;一奇一偶 -> 一奇一偶;一偶一奇 -> 一偶一奇;两奇 -> 两奇。

所以状态n+1的数量可以从状态n的数量中推出来,具体而言,{m, n, p, q}和{a, b, c, d}之间的关系就是:

m = b + c + a + a = 2a + b + c

n = a + d + b + b = a + 2b + d

p = d + a + c + c = a + 2c + d

q = c + b + d + d = b + c + 2d

有点fibonacci的感觉我们有,f[n+1] = f
* m,其中m是递推矩阵, m = [[2, 1, 1, 0], [1, 2, 0, 1], [1, 0, 2, 1], [0, 1, 1, 2]],初始条件f[1] = [2, 1, 1, 0],即

1、第一格染黄色或蓝色 => 两偶(都是0),有2种情况

2、第一格染红色 => 一奇一偶(红1绿0),有1种情况

3、第一格染绿色 => 一偶一奇(红0绿1),有1种情况

4、第一格不可能让红和绿都是奇数

从而f
= f[1] * m ^ (n-1),用矩阵快速幂可以达到O(logn)复杂度。



#include <cstdio>
#include <cstring>
#define MOD	10007

const int transfer[][4] = {{2, 1, 1, 0}, {1, 2, 0, 1}, {1, 0, 2, 1}, {0, 1, 1, 2}};
struct Matrix{
int a[4][4];
Matrix operator * (const Matrix& m)const{
Matrix t;
int i, j, k, s;
for(i = 0; i < 4; ++i){
for(j = 0; j < 4; ++j){
for(s = k = 0; k < 4; ++k) s = (s + a[i][k] * m.a[k][j]) % MOD;
t.a[i][j] = s;
}
}
return t;
}
};
Matrix power(const Matrix& matrix, int n)
{
if(n == 1) return matrix;

Matrix tmp = power(matrix, n >> 1);
if(n & 1) return tmp * tmp * matrix;
return tmp * tmp;
}

int main()
{
int t, n;
Matrix matrix, result;
memcpy(matrix.a, transfer, sizeof(matrix.a));
for(scanf("%d", &t); t--; ){
scanf("%d", &n);
if(n == 1){
puts("2");
continue;
}
result = power(matrix, n-1);
printf("%d\n", (result.a[0][0]*2 + result.a[1][0] + result.a[2][0]) % MOD);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: