【动态规划专练-区间DP】CF149D(1900)

【动态规划专练-区间DP】CF149D(1900)
题目大意:
给出能够配对的括号序列,按以下要求给括号上色:

  1. 一对括号必有一个染色,一个无色
  2. 相邻的有色括号不能是相同的颜色
    求上色方案数目,对1e9+7取模

思路:
由这一句
“ it is possible to obtain a correct mathematical expression from it, inserting numbers and operators between the brackets.”
我们知道,这里的括号序列必须是完全的包含或被包含的关系
所以可以预处理出匹配括号的位置:

int temp[1005],match[1005];string ss;
void getmatch(int len){
    int c = 0;
    for(int i=0;i<len;i++){
        if(ss[i] == '(') temp[c++] = i;
        else{
            match[i] = temp[c-1];
            match[temp[c-1]] = i;
            c--;
        }
    }
}

区间DP,研究左右边界。

  • 最后一步+子问题: 长的序列由短的序列得来,[l,r]若左右边界相等 则状态由[l+1,r-1]得来,不相等的话,则是[l,p] [p,r]的两个子区间转移得来。
  • 因为相邻括号之间有限制,而区间dp的状态都是加在边界上的,所以设状态转移方程: \(f[l][r][i][j]\)表示区间[l,r]两端颜色分别是i,j的涂色方案数目
  • 注意转移顺序:必须先计算小区间,再计算大区间
ll f[1005][1005][4][4];
int temp[1005],match[1005];string ss;
void getmatch(int len){
   int c = 0;
   for(int i=0;i<len;i++){
       if(ss[i] == '(') temp[c++] = i;
       else{
           match[i] = temp[c-1];
           match[temp[c-1]] = i;
           c--;
       }
   }
}
void dfs(int l,int r){
   if(l+1 == r){
       f[l][r][0][1] = 1;
       f[l][r][1][0] = 1;
       f[l][r][0][2] = 1;
       f[l][r][2][0] = 1;
       return ;
   }
   if(match[l] == r){
       dfs(l+1,r-1);
       for(int i=0;i<3;i++){
           for(int j=0;j<3;j++){
               if(j!=1)
                   f[l][r][0][1] += f[l+1][r-1][i][j],f[l][r][0][1]%=mod;
               if(i!=1)
                   f[l][r][1][0] += f[l+1][r-1][i][j],f[l][r][1][0]%=mod;
               if(j!=2)
                   f[l][r][0][2] += f[l+1][r-1][i][j],f[l][r][0][2]%=mod;
               if(i!=2)
                   f[l][r][2][0] += f[l+1][r-1][i][j],f[l][r][2][0]%=mod;
           }
       }
   }
   else{
       int p = match[l];
       dfs(l,p); dfs(p+1,r);
       for(int i=0;i<3;i++){    //注意转移顺序,先计算小区间再大区间,所以四个边界 i k q j
           for(int j=0;j<3;j++){ //i j 在最外层
               for(int k=0;k<3;k++){
                   for(int q=0;q<3;q++){
                       if(!((k==1&&q==1)||(k==2&&q==2)))
                           f[l][r][i][j]=(f[l][r][i][j]+(f[l][p][i][k]*f[p+1][r][q][j])%mod)%mod;
                   }
               }
           }
       }

   }
}
int main(){
   cin>>ss;
   int len = ss.length();
   getmatch(len);
   dfs(0,len-1);
   ll ans = 0;
   for(int i = 0; i < 3; i ++){
       for(int j = 0; j < 3; j ++){
           ans = (ans + f[0][len-1][i][j])%mod;
       }
   }
   cout << ans << endl;
   return 0;
}
posted @ 2021-09-14 17:49  qingyanng  阅读(45)  评论(1编辑  收藏  举报