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不一定匹配

posted @ 2021-02-11 21:02  acmloser  阅读(50)  评论(0编辑  收藏  举报