• Coloring Brackets CodeForces


    设dp[l][r][x][y]表示区间[l,r]左端染的色是x,右端染的色是y的方案数
    其中x,y取0,1,2,分别表示不染色,染红色,染蓝色

    1.l+1==r,那么它们一定就是一对匹配的括号,因为我们枚举的都是合理的情况,此时,只可能有四种情况,方案数均为1,即:dp[l][r][0][1] = dp[l][r][1][0] = 1;dp[l][r][0][2] = dp[l][r][2][0] = 1;
    2.l和r是一对匹配的括号,此时,区间被分为两部分,两端点以及区间[l+1,r-1],那么我们可以先算出区间[l+1,r-1]的方案数,再由此状态转移到当前区间,两端点情况也就四种,不冲突即可转移
    3.l和r不是一对匹配的括号,此时,区间也可被分成两部分,区间[l,mid]和区间[mid+1,r],其中mid为l所对应与之匹配的括号,这样,一个合法的括号序列变成两个合法的括号序列,将它们分别求出方案数,再将不冲突的情况组合起来即可

    //设dp[l][r][x][y]表示区间[l,r]左端染的色是x,右端染的色是y的方案数
    //其中x,y取0,1,2,分别表示不染色,染红色,染蓝色
    
    #include<iostream> 
    #include<stack>
    #include<map>
    using namespace std;
    typedef long long ll;
    const int maxn = 705;
    const int mod = 1000000007;
    ll dp[maxn][maxn][3][3];
    string str;
    stack<int> s;
    map<int, int> pos;
    //找当前括号对应匹配括号的下标
    void get_match() {
    	for (int i=0; i<str.size(); ++i) {
    		if (str[i] == '(')
    			s.push(i);
    		else {
    			pos[i] = s.top();
    			pos[s.top()] = i;
    			s.pop();
    		}
    	}
    }
    
    void dfs(int l, int r) {
    	//当区间长度只有2时候
    	//两个括弧一定是配对的,因为我们考虑的所有区间都是配对合法的区间
    	//
    	if (l+1 == r) {
    		dp[l][r][0][1] = dp[l][r][1][0] = 1;
    		dp[l][r][0][2] = dp[l][r][2][0] = 1;
    		return ;
    	}
    	//如果是匹配区间
    	if (pos[l] == r) {
    		//算里面的区间
    		dfs(l+1, r-1);
    		for (int i=0; i<3; ++i)
    			for (int j=0; j<3; ++j) {
    				//枚举所有情况,相邻的颜色不能相同 ,可以相邻两边都不染色
    				//但匹配的括号里面必须有一个染色,且只能由一个染色
    				//当区间尾部染色不为1
    				if (j != 1)
    					//开头不染,末尾染1
    					//								开头可以不染,但末尾颜色不能为1
    					dp[l][r][0][1] = (dp[l][r][0][1]+dp[l+1][r-1][i][j])%mod;
    				if (j != 2)
    					dp[l][r][0][2] = (dp[l][r][0][2]+dp[l+1][r-1][i][j])%mod;
    				if (i != 1)
    					dp[l][r][1][0] = (dp[l][r][1][0]+dp[l+1][r-1][i][j])%mod;
    				if (i != 2)
    					dp[l][r][2][0] = (dp[l][r][2][0]+dp[l+1][r-1][i][j])%mod;
    			}
    		return ;
    	}
    	//如果不是匹配区间
    	//去找匹配区间
    	int mid = pos[l];
    	dfs(l, mid);
    	dfs(mid+1, r);
    	//将两边的情况合并
    	for (int i=0; i<3; ++i)
    		for (int j=0; j<3; ++j)
    			for (int k=0; k<3; ++k)
    				for (int s=0; s<3; ++s)
    					if (!(k==1&&s==1) && !(k==2&&s==2))
    						dp[l][r][i][j] = (dp[l][r][i][j]+dp[l][mid][i][k]*dp[mid+1][r][s][j])%mod;
    }
    
    int main() {
    	cin >> str;
    	get_match();
    	dfs(0, str.size()-1);
    	ll ans = 0;
    	for (int i=0; i<3; ++i)
    		for (int j=0; j<3; ++j)
    			ans = (ans+dp[0][str.size()-1][i][j])%mod;
    	cout << ans << endl;
    	return 0;
    }
    
  • 相关阅读:
    JavaSE-28 hashCode()方法、equals()方法和==相关概念
    设计模式:命令模式(Command Pattern)
    Spring-02 Java配置实现IOC
    Spring-01 注解实现IOC
    [功能帮助类] 最新的Functions 类 (转载)
    C# DbHelperSQL,操作不同的数据库帮助类 (转载)
    C# DbHelperSQLP,操作不同的数据库帮助类 (转载)
    C# DbHelperSQLite,SQLite数据库帮助类 (转载)
    C#DbHelperOra,Oracle数据库帮助类 (转载)
    C#DbHelperOleDb,Access数据库帮助类 (转载)
  • 原文地址:https://www.cnblogs.com/QingyuYYYYY/p/12469161.html
Copyright © 2020-2023  润新知