K. Link with Bracket Sequence I(动态规划,“蔚来杯“2022牛客暑期多校训练营2)

发现牛客多校的题对我来说有点难,五个小时罚座就写出了一题,就只能看佬佬的题解补题了,我尽量按照我的理解把补题写的详细点,这样许多像我一样新手向的也能看懂了。

K. Link with Bracket Sequence I

K. Link with Bracket Sequence I

题目意思

给你一串长度为n的括号序列a,将其补全成长度为m的合法括号序列
问有多少种补全方案,答案对1e9+7取模。

分析

可以动态规划(我又想不到)

首先可以将'('看成是1,')'看成是-1,括号串序列合法就是其前缀和一直大
于等于0,且最后的和为0。
dp[i][j][k]代表将a串的前j个括号补成i个,且前缀和为k的方法数
那么动态转移方程有四种形式
① i位放置(,且s[j]!=(  或者j为0
  dp[i][j][k]=dp[i][j][k]+dp[i-1][j][k-1]
② 	i位放置( ,且s[j]=(
	dp[i][j][k]=dp[i][j][k]+dp[i-1][j-1][k-1]
③ i位放置),且s[j]!=)或j为0
  dp[i][j][k]=dp[i][j][k]+dp[i-1][j][k+1]
④ i位放置),且s[j]=)
  dp[i][j][k]=dp[i][j][k]+dp[i-1][j-1][k+1]

①和②的情况,由于要前缀和一直大于等于0,所以k>=1
最后就是要考虑边界 dp[0][0][0]=1

代码

#include<bits/stdc++.h>
using namespace std;
#define double long double 
typedef long long ll;
const ll mod=1e9+7;
const ll inf=0x3f3f3f3f;
const double eps=1e-10;
ll dp[300][300][300];
char ch[300];


void solve()
{
	ll n,m,i,j,k;
	cin>>n>>m;
	cin>>ch;
	for(i=n;i>=1;i--) ch[i]=ch[i-1];
	for(i=1;i<=m;i++)
	{
		for(j=0;j<=min(n,i);j++)
		{
			for(k=0;k<=i;k++)
			{
				dp[i][j][k]=0;
			}
		}
	}
	dp[0][0][0]=1;
	for(i=1;i<=m;i++)
	{
		for(j=0;j<=min(n,i);j++)
		{
			for(k=0;k<=i;k++)
			{
//				i位放置(,且s[j]!=(  
//				dp[i][j][k]=dp[i][j][k]+dp[i-1][j][k-1]
				if((ch[j]!='('||j==0)&&k>=1) 
				{
					dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k-1])%mod;
				}
//				i位放置( ,且s[j]=(
//				dp[i][j][k]=dp[i][j][k]+dp[i-1][j-1][k-1]
				if(k>=1&&j>=1&&ch[j]=='(')
				{
					dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k-1])%mod;
				} 
//				i位放置),且s[j]!=)
//				dp[i][j][k]=dp[i][j][k]+dp[i-1][j][k+1]
				if(ch[j]!=')'||j==0)
				{
					dp[i][j][k]=(dp[i][j][k]+dp[i-1][j][k+1])%mod;
				} 
//				i位放置),且s[j]=)
//				dp[i][j][k]=dp[i][j][k]+dp[i-1][j-1][k+1]
				if(j>=1&&ch[j]==')')
				{
					dp[i][j][k]=(dp[i][j][k]+dp[i-1][j-1][k+1])%mod;
				}
			}
		}
	}
	cout<<dp[m][n][0]<<endl;
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    int t=1;
    cin>>t;
    while(t--)
    {
        solve();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值