POJ-3734(DP + 矩阵求幂)

题目: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[n] * 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[n] = 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值