【2022牛客多校第二场】K-Link with Bracket Sequence I

赛后感受

这场打下来有点坐牢,K题当时想假了,当时想的是组合数学+暴搜但是没有成功。没想到下来是DP,感觉有点亏,毕竟动归的本质还是组合数学,当时没有DP出来现在就来补题一下。顺便写个blog加深一下印象。
原题链接

题的大意:
在这里插入图片描述
给一个子串长度和原串长度。
再给的是一个子串(A) ,让求有多少个合法原串(B)

解题思路:
DP思想:设前 i 个B里最多匹配到前 j 个A ,也就是求有多少在可能的B的方案数
这时候还需要注意仅用i j 标记的dp不一定合法,因此dp设计为三维 再设计一个K来判断知否合法,判断思路为有 K左括号未被匹配:不为零,即为不合法
状态转移过程:
在这里插入图片描述
现在考虑 如果在前i个B后面加一个左括号会怎么样

得到转移方程:dp(i,j,k)->dp(i+1,j,k)
再考虑,如果A的j+1是左括号就能匹配上,如果不是就不能匹配上

如果是
dp(i,j,k)->dp(i+1,j+1,k+1)
如果不是
dp(i,j,k)->dp(i+1,j,k+1)
如果是右括号 还需要看一下k是否不为零,即有未匹配的左括号
AC代码:

#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define Buff std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
const int N = 205;
const int mod = 1e9 + 7;
int t, n, m;
int dp[N][N][N];
signed main()
{
    
    
  Buff;
  cin >> t;
  
  while (t--)
  {
    
    
    cin >> n >> m;
    string s;
    cin >> s;
    s = " " + s;
    for (int i = 0; i <= m; i++)
      for (int j = 0; j <= n; j++)
        for (int k = 0; k <= i; k++) // k到i即可
        {
    
    
          dp[i][j][k] = 0;
        }
    dp[0][0][0] = 1; //初始化 空序列没有剩任何的括号
    for (int i = 0; i <= m; i++)
    {
    
    
      for (int j = 0; j <= n; j++)
      {
    
    
        for (int k = 0; k <= i; k++)
        {
    
    
          if (!dp[i][j][k])
            continue;
          if (s[j + 1] == '(')
            dp[i + 1][j + 1][k + 1] = (dp[i + 1][j + 1][k + 1] + dp[i][j][k]) % mod;//推出来的状态转移方程
          else
            dp[i + 1][j][k + 1] = (dp[i + 1][j][k + 1] + dp[i][j][k]) % mod;

          if (k)
            if (s[j + 1] == ')')
              dp[i + 1][j + 1][k - 1] = (dp[i + 1][j + 1][k - 1] + dp[i][j][k]) % mod;
            else
              dp[i + 1][j][k - 1] = (dp[i + 1][j][k - 1] + dp[i][j][k]) % mod;
        }
      }
    }

    cout << dp[m][n][0] << endl;
  }

  return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_45148277/article/details/126002100