Coloring Brackets CodeForces - 149D
考察:区间dp+记忆化搜索(可有可无)
本蒟蒻是完全没思路...参考大佬的代码
参考大佬的思路:
参考括号匹配的dp题,这道题也是分为(())和()()型.但dp数组有所不同,根据()左右括号颜色的不同,里层或者断点f[i,k]会有不同方案数.以(())为例,14颜色的不同使得里层对应的方案数不同.我们可以记录l,r左右颜色.那么答案就是累加所有左右不同的颜色.
(())型,根据里层括号的颜色外层括号对应唯一的取值,所以答案是f[l][r]+=f[l+1][r-1]
()()型,根据左边不同的取值右边可以有多个取值,所以答案是f[l][r] += f[l][ml]*f[ml+1][r].实际是将本种化为第一种处理.
注意:ml+1和r可以都有颜色,因为它们不一定相邻且不一定对应相同的括号
再再注意:相乘记得long long
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <map> 6 #include <stack> 7 using namespace std; 8 typedef long long ll; 9 const int N = 710,Mod = 1e9+7; 10 stack<int> stk; 11 char s[N]; 12 int n,match[N],f[N][N][3][3],res; 13 void matchs() 14 { 15 for(int i=1;i<=n;i++) 16 { 17 if(s[i]=='(') stk.push(i); 18 else{ 19 match[stk.top()] = i; 20 stk.pop(); 21 } 22 } 23 } 24 void dfs(int l,int r) 25 { 26 if(l==r-1) 27 { 28 f[l][r][1][0] = 1,f[l][r][2][0] = 1; 29 f[l][r][0][1] = 1,f[l][r][0][2] = 1; 30 } 31 else if(match[l]==r) 32 { 33 dfs(l+1,r-1); 34 for(int i=0;i<3;i++) 35 for(int j=0;j<3;j++) 36 { 37 if(i!=1) f[l][r][1][0] = (f[l][r][1][0]+f[l+1][r-1][i][j])%Mod; 38 if(i!=2) f[l][r][2][0] = (f[l][r][2][0]+f[l+1][r-1][i][j])%Mod; 39 if(j!=1) f[l][r][0][1] = (f[l][r][0][1]+f[l+1][r-1][i][j])%Mod; 40 if(j!=2) f[l][r][0][2] = (f[l][r][0][2]+f[l+1][r-1][i][j])%Mod; 41 } 42 }else{ 43 dfs(l,match[l]); 44 dfs(match[l]+1,r);//match[l]+1一定是(,因为如果是嵌套(()),按照先后顺序我们会先找到后面的括号,如果是()()很明显符合 45 int ml = match[l]; 46 for(int i=0;i<3;i++) 47 for(int j=0;j<3;j++) 48 for(int x=0;x<3;x++) 49 for(int y=0;y<3;y++) 50 { 51 if(x==y&&(x==1||x==2)) continue; 52 f[l][r][i][j] = (f[l][r][i][j]+(long long)f[l][ml][i][x]*f[ml+1][r][y][j]%Mod)%Mod; 53 } 54 } 55 } 56 int main() 57 { 58 scanf("%s",s+1); 59 n = strlen(s+1); 60 matchs(); 61 dfs(1,n); 62 for(int i=0;i<3;i++) 63 for(int j=0;j<3;j++) 64 res = (res+f[1][n][i][j])%Mod; 65 printf("%d\n",res); 66 return 0; 67 }
关于这道题为什么用记忆化搜索:
普通的区间dp模板也可以,这里有大佬是用普通的区间dp GO.
有些大佬说可能会有不合法的序列,当取到右括号),它的match[i] = 0.凭借这个可以去除不合法的序列的影响.也不用担心match[l]+1对答案的影响,dp[i][0]永远为0
用记忆化搜索l一定取到合法的左括号,但for循环不一定.只要取到(算法基本一致
2021.3.17二刷,想到了四维数组但是没做出来,match[i]==j那里大佬写的很简洁,我是只想到两个for...而且直接写得s[i]=='(&&s[j]=='),这是错的,因为不一定匹配.这里有点像括号匹配那题,虽然f[i][j] = f[i+1][j-1],但是还要寻找断点,因为i与j不一定匹配