POJ-3734 Blocks

題目大意:

有n個blocks,讓你用紅,藍,綠,黃四種顏色染上色,其中紅色和綠色的block都是偶數個的方案有多少個。

解題思路:

其實這是個DP...啊一臉狗血...

其實模型很像這題....HDU 1143 Tri Tiling

首先,假設dp[i][0]表示當塗了前i個blocks之後,紅色和綠色都是偶數個的方案個數,dp[i][1]表示當塗了前i個blocks之後,紅色和綠色只有一個是偶數個的方案個數,dp[i][2]表示當塗了前i個blocks之後,紅色和綠色都不是偶數個的方案個數

那麼狀態轉移爲:

dp[i+1][0] = 2 * dp[i][0] + dp[i][1] 

表示塗了前i+1個之後紅色和綠色都是偶數個,那麼前i個可以是紅色和綠色都是偶數個,第i+1個選擇藍色或黃色,或者前i個是紅色和綠色有一個是偶數個,那麼第i+1個選擇爲不是偶數個的那一個。

以此類推。得出所有的狀態轉移:

dp[i+1][0] = 2 * dp[i][0] + dp[i][1]

dp[i+1][1] = 2 * dp[i][0] + 2 * dp[i][1] + 2 * dp[i][2]

dp[i+1][2] = dp[i][1] + 2 * dp[i][2]

如果你以爲就這麼結束那真是亦可賽艇...這題關鍵在於n數量級極大,即使你用滾動數組去維護依舊無法拜託超時的厄運。所以需要加速。

於是矩陣快速冪誕生了。(xjb扯的

怎麼轉換矩陣快速冪可以參考斐波那契數列...

代碼:

#include <cstdio>
#include <cstring>
using namespace std;

const int mod = 10007;
typedef struct node {
	int mat[4][4];
	node() { memset(mat, 0, sizeof(mat)); }
}Matrix;

Matrix operator * (Matrix a, Matrix b) {
	Matrix ans;
	for (int i = 0; i < 3; ++i)
		for (int j = 0; j < 3; ++j)
			for (int k = 0; k < 3; ++k)
				ans.mat[i][j] = (ans.mat[i][j] + a.mat[i][k] * b.mat[k][j]) % mod;
	return ans;
}
Matrix operator ^ (Matrix a, int num) {
	Matrix ans;
	for (int i = 0; i < 3; ++i) ans.mat[i][i] = 1;
	while (num) {
		if (num & 1) ans = ans * a;
		a = a * a;
		num >>= 1;
	}
	return ans;
}
int main() {
	int n, t;
	scanf("%d", &t);
	while (t--) {
		Matrix m;
		scanf("%d", &n);
		m.mat[0][0] = 2; m.mat[0][1] = 1; m.mat[0][2] = 0;
		m.mat[1][0] = 2; m.mat[1][1] = 2; m.mat[1][2] = 2;
		m.mat[2][0] = 0; m.mat[2][1] = 1; m.mat[2][2] = 2;
		m = m ^ n;
		printf("%d\n", m.mat[0][0]);
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章