CF149D 【Coloring Brackets】

这道题本质上不难,但是很麻烦,很恶心。

我看了一下,市面上的题解基本都是用\(dfs\)的方式来演绎这个\(dp\),而且有一些雷同于单调,下面,我用区间\(dp\)的角度来演绎这道题。

我们姑且先定义\(dp_{i,j,0}\)为对区间\([i,j]\)染色的方案数。

我们先考虑转移,然后根据转移再完善我们的定义。

考虑两种情况

1、对于一个括号串,他由一对单调的括号里面加上一些串组成

2、对于一个括号串,他由数对单调的括号里面加上一些串组成

对于第一种情况:

在外面的一对括号串可以有四种方式进行染色,但是却存在冲突。因为相邻的两个括号颜色不能相同,那么根据融斥的思想,我们想要算出冲突的情况。因为对于每一种外层染色的情况,我们都可以把与他相邻的一个括号染成固定的颜色,从而达到冲突的目的。

由此,为了避免计算逆元我们定义\(dp_{i,j,1}\)为区间\([i,j]\)中串首染一种固定颜色的方案总数。得到转移方程如下:

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $ \(dp_{i,j,0}\) = \(4 * (dp_{i+1,j-1,0} - dp_{i+1,j-1,1})\)

但是\(dp_{i,j,1}\)怎么转移呢?我们给串首固定一种颜色,那么包含在里面的串当且仅当在里面的串的串首与他颜色一致,减去即可。

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $ \(dp_{i,j,1}\) = \(dp_{i+1,j-1,0} - dp_{i+1,j-1,1}\)

对于第二种情况:

根据乘法原理,先找到第一个单调括号的结尾,然后将两段相乘,再减去冲突部分,即两段相接的地方一样的时候,即为两段首颜色确定且相同的情况,有两种颜色,所以\(*2\)

\(f\)为交界处,则有\(dp\)式为:

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $ \(dp_{i,j,0}\) = \(dp_{i,f,0} * dp_{f+1,j,0} - dp_{i,f,1} * dp_{f+1,j,1} * 2\)

对于\(dp_{i,j,1}\)很简单,首位确定就与后面没什么关系了,直接乘上即可。

$\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ $ \(dp_{i,j,1}\) = \(dp_{i,f,1} * dp_{f,j,0}\)

以上是我根据排列组合的思想推出的\(dp\)式,希望能对大家的对\(dp\)的推导与理解有帮助。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int mod = 1000000007;
char s[705];
int dp[705][705][2] , n;
int pd(int x , int y) { // 用栈的方式判断。
	int f = 1 , top = 0;
	for (int i = x; i <= y; ++i) {
		if(s[i] == '(') top ++;
		else top --;
		if(top < 0) return 0;
		if(!top && i != y && f == 1) f = i;
	}
	if(top != 0) return 0;
	return f;
}
int main() {
	scanf("%s" , s + 1);
	n = strlen(s + 1);
	for (int len = 2; len <= n; len += 2) {
		for (int i = 1; i <= n; ++i) {
			int j = i + len - 1;
			if(len == 2) {
				if(s[i] == '(' && s[j] == ')') {
					dp[i][j][0] = 4;
					dp[i][j][1] = 1;//特判
				}
				continue;
			}
			int f = pd(i , j);//这个地方的判断可以在之前预处理出来,但我看见不预处理也能过就不管了。
			if(!f) continue;
			else if(f == 1) {
				dp[i][j][0] = (4ll * (long long)(dp[i + 1][j - 1][0] - dp[i + 1][j - 1][1]) % mod + mod) % mod;
				dp[i][j][1] = ((dp[i + 1][j - 1][0] - dp[i + 1][j - 1][1]) % mod + mod) % mod;
			}
			else {
				dp[i][j][0] = (long long)dp[i][f][0] * (long long)dp[f + 1][j][0] % mod - (long long) dp[i][f][1] * (long long)dp[f + 1][j][1] * 2ll % mod;
				dp[i][j][0] = (dp[i][j][0] % mod + mod) % mod;
				dp[i][j][1] = (long long)dp[i][f][1] * (long long)dp[f + 1][j][0] % mod; 
			}//dp转移
		}
	}
	printf("%d" , dp[1][n][0]);
	return 0;
}

posted @ 2020-08-02 21:21  Reanap  阅读(90)  评论(0编辑  收藏  举报