zoukankan      html  css  js  c++  java
  • CF149D Coloring Brackets

    前言

    【题目传送门】
    并不是很难的一道题,但仍有值得学习之处。

    题解

    区间 DP 显然能看出。
    而且对于配对的两个括号,肯定是要一起处理。
    所以预处理每个括号配对的位置也能想到。
    也能想到根据两个端点是否配对,分类讨论加法和乘法。

    我遇到的问题

    • 原本设计的 DP 没有只记录了左右括号分别涂某种颜色的情况,这样的话如果区间左右括号不配对就没办法转移了。
    • 想写记搜,但是想到 solve 函数里面还要传入 (op),就不知道该返回什么了。(其实是我 sb 了,如果分情况返回值应该也是可以写的,只不过就略微冗杂了一点,这充分说明我很菜)
    • 分类讨论的时候还有个判断写错了。

    正解的思路

    • 记录 (dp(l,r,i,j)) 表示区间内左右端点不涂色/红色/蓝色的方案数。
    • 貌似只能写搜索,因为要保证配对的括号在同一区间。
    • 分情况转移两端是否配对的情况。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define FCC fclose(stdin),fclose(stdout)
    const int INF = 0x3f3f3f3f,mod = 1e9+7,N = 706;
    inline ll read()
    {
    	ll ret=0;char ch=' ',c=getchar();
    	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
    	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
    	return ch=='-'?-ret:ret;
    }
    ll dp[N][N][3][3];
    int n,rit[N];
    int stk[N],top;
    char s[N];
    inline ll Mod(ll x,ll y)
    {
    	return ((x+y)%mod+mod)%mod;
    }
    void solve(int l,int r)
    {
    	if(l+1==r) 
    	{
    		dp[l][r][0][1]=dp[l][r][0][2]=dp[l][r][1][0]=dp[l][r][2][0]=1;
    		return;
    	}
    	if(rit[l]==r)
    	{
    		solve(l+1,r-1);
    		for(int i=0;i<=2;i++)
    			for(int j=0;j<=2;j++)
    			{
    		        if(j!=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;
    			}
    	}
    	else 
    	{
    		solve(l,rit[l]),solve(rit[l]+1,r);
    		for(int i=0;i<=2;i++)	
    			for(int j=0;j<=2;j++)
    				for(int k=0;k<=2;k++)		
    					for(int p=0;p<=2;p++)
    					{
    					//	if((k==p&&k)||(i==k&&k)||(p==j&&p)) continue;
    						if(k==p&&p) continue;
    						dp[l][r][i][j]=Mod(dp[l][r][i][j],
    						dp[l][rit[l]][i][k]*dp[rit[l]+1][r][p][j]%mod);
    					}
    	}
    }
    int main()
    {
    	scanf("%s",s+1);
    	n=strlen(s+1);
    	for(int i=1;i<=n;i++)	
    	{
    		if(s[i]=='(') stk[++top]=i;
    		else rit[stk[top--]]=i;
    	}
    	solve(1,n);
    	ll ans=0ll;
    	for(int i=0;i<=2;i++)	
    		for(int j=0;j<=2;j++)	
    			ans=(ans+dp[1][n][i][j])%mod;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    线程间的通信 与 线程池
    线程同步
    静态代理模式
    多线程状态
    线程、进程、多线程
    Java面向对象之泛型
    ConstraintLayout 用法
    搞NDK开发
    Linux基础命令【记录】
    c# 的一些基本操作或属性
  • 原文地址:https://www.cnblogs.com/conprour/p/15536245.html
Copyright © 2011-2022 走看看