zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
  • 相关阅读:
    go if 判断 完成随机分数的评级
    go for循环
    go 常量2
    go 常量定义和使用
    更新数据库某字段数据为流水号
    BPM设定操作超时
    BPM打印按钮
    BPM链接处理
    项目管理
    公司规划
  • 原文地址:https://www.cnblogs.com/Reanap/p/13423242.html
Copyright © 2011-2022 走看看