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

博主回顾了一次比赛中的经历,原本计划使用组合数学和暴搜方法解题,但实际题目涉及DP。文章详细解析了如何运用动态规划求解给定子串长度和原串长度下合法原串的数目,同时分享了状态转移方程和AC代码。通过写博客加深理解并补全了缺失的解题思路。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

赛后感受

这场打下来有点坐牢,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值