题意:给我们字符串n和n的长度,让我们构造一个长度为m的字符串,使得n是m的子串,问有几种构造方式
肯定是一道dp
我们设表示我们构造了长度为i的字符串,已经和n匹配了j个字符,并且左括号比右括号多k个
每当我们多构造一个,要么放左括号要么放右括号
如果正好匹配上了,那就可以从转移过来
有
如果没匹配上,从转移过来
有
注意特判下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;
}