CodeForces 149D Coloring Brackets(区间dp)
题意:
给一个给定括号序列,给该括号上色,上色有三个要求
1、只有三种上色方案,不上色,上红色,上蓝色
2、每对括号必须只能给其中的一个上色
3、相邻的两个不能上同色,可以都不上色
求0-len-1这一区间内有多少种上色方案
我按最基本的区间dp思路果断跑了810ms,看了别人30ms的代码。。
就是要找0到n-1区间的方案数,当用到l到r区间的方案数时递归找l到r区间方案数
这样就省去记录所有的状态了
因为如果i与j不匹配的时候,只需要找到i到u和u+1到j的方案数就可以了(u为与i匹配的括号)
附上我的渣渣代码~
#include <iostream> #include <algorithm> #include <cstring> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <cstdio> using namespace std; const int mod=1e9+7; char s[710]; int n,mapp[710]; long long dp[710][710][3][3]; void getmap() { memset(mapp,0,sizeof(mapp)); stack<int>q; while(!q.empty()) q.pop(); for(int i=0; i<n; i++) { if(s[i]=='(') q.push(i); else { if(q.empty()) continue; int p=q.top(); q.pop(); mapp[p]=i; mapp[i]=p; } } } void solve() { while(~scanf("%s",s)) { n=strlen(s); getmap(); memset(dp,0,sizeof(dp)); for(int i=0; i<n-1; i++) { dp[i][i+1][0][1]=dp[i][i+1][0][2]=dp[i][i+1][1][0]=dp[i][i+1][2][0]=1; if(mapp[i]!=i+1) dp[i][i+1][0][0]=dp[i][i+1][1][2]=dp[i][i+1][2][1]=1; } for(int l=2; l<n; l++) { for(int i=0; i+l<n; i++) { int j=i+l; if(mapp[i]==j) { for(int p=0; p<=2; p++) { for(int q=0; q<=2; q++) { if(q!=1) dp[i][j][0][1]=(dp[i][j][0][1]+dp[i+1][j-1][p][q])%mod; if(p!=1) dp[i][j][1][0]=(dp[i][j][1][0]+dp[i+1][j-1][p][q])%mod; if(q!=2) dp[i][j][0][2]=(dp[i][j][0][2]+dp[i+1][j-1][p][q])%mod; if(p!=2) dp[i][j][2][0]=(dp[i][j][2][0]+dp[i+1][j-1][p][q])%mod; } } } else { int u=mapp[i]; for(int p=0; p<=2; p++) for(int q=0; q<=2; q++) for(int x=0; x<=2; x++) for(int y=0; y<=2; y++) if(!((x==1&&y==1)||(x==2&&y==2))) dp[i][j][p][q]=(dp[i][j][p][q]+(dp[i][u][p][x]*dp[u+1][j][y][q])%mod)%mod; } } } long long ans=0; for(int i=0; i<=2; i++) for(int j=0; j<=2; j++) ans=(ans+dp[0][n-1][i][j])%mod; printf("%lld\n",ans); } } int main() { //freopen("in.txt","r",stdin); solve(); return 0; }