• codeforces 149D Coloring Brackets (区间DP + dfs)


    题目链接:

      codeforces 149D Coloring Brackets

    题目描述:

      给一个合法的括号串,然后问这串括号有多少种涂色方案,当然啦!涂色是有限制的。

      1,每个括号只有三种选择:涂红色,涂蓝色,不涂色。

      2,每对括号有且仅有其中一个被涂色。

      3,相邻的括号不能涂相同的颜色,但是相邻的括号可以同时不涂色。

    解题思路:

      这个题目的确是一个好题,无奈我太蠢,读错题意。以为(())这样的括号序列在涂色的时候,第一个括号与第三个括号也可以看做是一对。这样的话还要统计合法的括号匹配数目,还要计算涂色的方案。然后想了好久好久。最后发现并不是这样的,给出的括号序列,括号的匹配都是固定的,也就是说只需要给这些固定匹配的括号按照上面限制涂色就好啦。

      可以定义 dp[l][r][x][y] 表示区间 [l, r] 在左端点涂x色,右端点涂y色的情况下的方案数。其中0代表不涂色, 1代表涂红色, 2代表涂蓝色。

      窝们可以把括号序列可以分为两类分别进行状态转移:

      括号套括号,状态转移是:dp[l][r][x][y] += dp[l+1][r-1][x'][y'] (0<=x'<3, x'!=x, 0<=y'<3, y!=y')

      多个匹配串连起来,转台转移是:dp[l][r][x][y] += dp[l][nu][x'][y'] * dp[nu][r][x''][y''] (nu是l对应的另一边括号)

      当l+1 == r的时候有:dp[l][r][0][1] = 1;  dp[l][r][1][0] = 1;

                 dp[l][r][0][2] = 1;  dp[l][r][2][0] = 1;

     1 #include <cmath>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <iostream>
     5 #include <algorithm>
     6 using namespace std;
     7 
     8 typedef __int64 LL;
     9 const LL mod = 1000000007;
    10 const LL maxn = 710;
    11 LL dp[maxn][maxn][3][3], match[maxn], tep[maxn];
    12 
    13 void get_macth (char a[])
    14 {
    15     int p = 0;
    16     for (int i=0; a[i]; i++)
    17     {
    18         if (a[i] == '(')
    19             tep[p ++] = i;
    20         else
    21         {
    22             match[i] = tep[p-1];
    23             match[tep[p-1]] = i;
    24             p --;
    25         }
    26     }
    27 }
    28 
    29 void dfs (int l, int r)
    30 {
    31     if (l + 1 == r)
    32     {
    33         dp[l][r][0][1] = 1;
    34         dp[l][r][1][0] = 1;
    35         dp[l][r][0][2] = 1;
    36         dp[l][r][2][0] = 1;
    37         return ;
    38     }
    39     
    40     else if (match[l] == r)
    41     {
    42         dfs (l+1, r-1);
    43         for (int i=0; i<3; i++)
    44             for (int j=0; j<3; j++)
    45             {
    46                 if (j != 1)
    47                     dp[l][r][0][1] = (dp[l][r][0][1] + dp[l+1][r-1][i][j]) % mod;
    48                 if (i != 1)
    49                     dp[l][r][1][0] = (dp[l][r][1][0] + dp[l+1][r-1][i][j]) % mod;
    50                 if (j != 2)
    51                     dp[l][r][0][2] = (dp[l][r][0][2] + dp[l+1][r-1][i][j]) % mod;
    52                 if (i != 2)
    53                     dp[l][r][2][0] = (dp[l][r][2][0] + dp[l+1][r-1][i][j]) % mod;
    54             }
    55         return ;
    56     }
    57     
    58     else
    59     {
    60         int nu = match[l];
    61         dfs (l, nu);
    62         dfs (nu+1, r);
    63 
    64         for (int i=0; i<3; i++)
    65             for (int j=0; j<3; j++)
    66                 for (int x=0; x<3; x++)
    67                     for (int y=0; y<3; y++)
    68                         if (!(x==1&&y==1 || x==2&&y==2))
    69                         dp[l][r][i][j] = (dp[l][r][i][j] + dp[l][nu][i][x]*dp[nu+1][r][y][j]) % mod;
    70     }
    71     
    72 }
    73 
    74 int main ()
    75 {
    76     char s[maxn];
    77     
    78     while (scanf ("%s", s) != EOF)
    79     {
    80         memset(dp, 0, sizeof(dp));
    81         int len = strlen (s);
    82         get_macth (s);
    83         dfs (0, len-1);
    84 
    85         LL ans = 0;
    86         for (int i=0; i<3; i++)
    87             for (int j=0; j<3; j++)
    88                 ans = (ans + dp[0][len-1][i][j]) % mod;
    89         printf ("%I64d
    ", ans);
    90         
    91     }
    92     return 0;
    93 }
    本文为博主原创文章,未经博主允许不得转载。
  • 相关阅读:
    实时日历
    添加与删除
    php 变量 循环关键词以及方法
    php中各种操作字符串和时间戳的代码关键词
    php中数组相关
    php中普通方法和静态方法的区别以及抽象类和接口
    php设计模式 工厂模式和单例
    面对对象7大原则整理
    PHP中include与require的特点和区别说明
    php基础运算符语句
  • 原文地址:https://www.cnblogs.com/alihenaixiao/p/4936802.html
Copyright © 2020-2023  润新知