dp Regular QBXT Test Ⅸ T1

题意:给出一个只包含左括号和右括号的字符串,插入若干左右括号(可以插在任意位置)之后使得字符串长度为 2 n 2n 2n且是一个合法的括号序列。求最后能组成多少种不同的合法括号序列。【合法的括号序列:该序列任意一个前缀的左括号数大于等于右括号数,最终左括号数等于右括号数】。 n &lt; = 100 n&lt;=100 n<=100

三维 d p dp dp d p dp dp的前两维分别为插入的括号数量和使用的原来的序列中的括号数量,而第三维是用来判断合法性的,所以第三维设为左括号比右括号多的数量。状态设计出来后,转移就比较好想了,设 m m m为读入的括号序列的长度。首先枚举插入的括号数量,原来的括号序列和左括号比右括号多的数量。首先如果目前枚举到的括号为左括号,并且使用的原括号的数量 &lt; m &lt;m <m,就可以将该括号放入最终序列中,即为: d p [ i ] [ j + 1 ] [ k + 1 ] + = d p [ i ] [ j ] [ k ] dp[i][j+1][k+1]+=dp[i][j][k]%mod+dp[i][j][k]%mod)%mod; dp[i][j+1][k+1]+=dp[i][j][k]

如果此时枚举到的是一个右括号,并且 k &gt; 0 k&gt;0 k>0,即左括号的数量大于右括号的数量,并且使用的原括号的数量 &lt; m &lt;m <m,就将该右括号放入最终序列,即为: d p [ i ] [ j + 1 ] [ k − 1 ] + = d p [ i ] [ j ] [ k ] dp[i][j+1][k-1]+=dp[i][j][k]%mod+dp[i][j][k]%mod)%mod; dp[i][j+1][k1]+=dp[i][j][k]

如果使用的括号数量 = m =m =m,或当前枚举到的是一个右括号,可以插入一个左括号。即为: d p [ i + 1 ] [ j ] [ k + 1 ] + = d p [ i ] [ j ] [ k ] dp[i+1][j][k+1]+=dp[i][j][k]%mod+dp[i][j][k]%mod)%mod; dp[i+1][j][k+1]+=dp[i][j][k]

k &gt; 0 k&gt;0 k>0时,如果使用的括号数量 = m =m =m,或当前枚举到的是一个左括号,可以插入一个右括号。即为: d p [ i + 1 ] [ j ] [ k − 1 ] + = d p [ i ] [ j ] [ k ] dp[i+1][j][k-1]+=dp[i][j][k]%mod+dp[i][j][k]%mod)%mod; dp[i+1][j][k1]+=dp[i][j][k]

答案就是 d p [ 2 ∗ n − m ] [ m ] [ 0 ] dp[2*n-m][m][0] dp[2nm][m][0]

#include<bits/stdc++.h>
using namespace std;
int dp[220][220][220],n;
const int mod=1e9+7;
//dp[i][j][k]表示已经插入i个字符,使用原串j个字符且左括号比右括号多k个的方案数
char s[10000];
int main()
{
	freopen("regular.in","r",stdin);
	freopen("regular.out","w",stdout);	
	cin>>n;
	scanf("%s",s);
	int m=strlen(s);
	dp[0][0][0]=1;
	for(int i=0;i<=2*n-m;++i)
		for(int j=0;j<=m;++j)
			for(int k=0;k<=n;++k)
			{
				if(s[j]=='('&&j<m)
					dp[i][j+1][k+1]=(dp[i][j+1][k+1]%mod+dp[i][j][k]%mod)%mod;
				else 
					dp[i+1][j][k+1]=(dp[i+1][j][k+1]%mod+dp[i][j][k]%mod)%mod;
				if(k>0)
				{
					if(s[j]==')'&&j<m)
						dp[i][j+1][k-1]=(dp[i][j+1][k-1]%mod+dp[i][j][k]%mod)%mod;
					else
						dp[i+1][j][k-1]=(dp[i+1][j][k-1]%mod+dp[i][j][k]%mod)%mod;				
				}		
			}
	cout<<dp[2*n-m][m][0];
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值