“蔚来杯“2022牛客暑期多校训练营2 K Link with Bracket Sequence I(括号dp)

题意:给我们字符串n和n的长度,让我们构造一个长度为m的字符串,使得n是m的子串,问有几种构造方式

肯定是一道dp

我们设f[i][j][k]表示我们构造了长度为i的字符串,已经和n匹配了j个字符,并且左括号比右括号多k个

每当我们多构造一个,要么放左括号要么放右括号

如果正好匹配上了,那就可以从f[i-1][j-1][k-1]转移过来

f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k-1])

如果没匹配上,从f[i-1][j][k-1]转移过来

f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1])

注意特判下j等于0,i和k的边界情况

还有注意下他数据到200,牛客数组开500*500*500内存就爆了

清空f的时候用m,n,m清空

别用memset,也别全清空,都会t掉

代码如下

#include <bits/stdc++.h>
#include <iomanip>
#define fer(i,a,b) for(int i=a;i<=b;i++)
#define der(i,a,b) for(int i=a;i>=b;i--)
#define int long long
#define pb push_back
#define pll pair<int,int>
#define ld long double
#define x first
#define y second
using namespace std;
const int N=1e6+10;
template <typename _Tp>void input(_Tp&x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp&t,Args&...args){input(t);input(args...);}
char s[305];
int f[305][305][305];
const int mod=1e9+7;
signed main()
{
	int T;
	input(T);
	while(T--){
		int n, m;
		input(n,m);
        fer(i,0,m)fer(j,0,n)fer(k,0,m) f[i][j][k]=0;
		scanf("%s", s+1);
		if(s[1]=='(') f[1][1][1]=1;//因为第一个只能放左括号,如果匹配上了f[1][1][1]就等于1
		f[1][0][1]=1;
		fer(i,2,m){
			fer(j,0,n){
				fer(k,0,m){
                    if(j==0){
                        if(k>=1){ 
							f[i][0][k]=(f[i][0][k]+f[i-1][0][k-1])%mod;
                        }
						//放右括号
						if(k<=m-1){
							f[i][0][k]=(f[i][0][k]+f[i-1][0][k+1])%mod;
                        }
                        continue;
                    }
                    //放左括号
                    if(s[j]=='('&&k>=1){
                        f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k-1])%mod;
                    }
                    else if(s[j]==')'&&k >=1){
                        f[i][j][k]=(f[i][j][k]+f[i-1][j][k-1])%mod;
                    }
                    //放右括号
                    if(s[j]==')'&&k<=m-1){
                        f[i][j][k]=(f[i][j][k]+f[i-1][j-1][k+1])%mod;
                    }
                    else if(s[j]=='('&&k<=m-1){
                        f[i][j][k]=(f[i][j][k]+f[i-1][j][k+1])%mod;
                    }
					
				}
            }
        }
		cout<<f[m][n][0]<<'\n';
	}
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值