题目连接:F. Bracket Substring
题意:输入一个数字n,和只有左右括号的s串,问有多少个长度为2*n完美串有s作为连续字串
题解:dp+kmp的nxt数组。dp[i][j][k]表示那个2*n的串匹配到i这个位置有j个位置匹配,还有k个不匹配左括号的方案数
状态转移时,要借助nxt数组处理出来的f[]数组,f[i]表示在第i个位置不匹配然后它能与原串开头匹配的长度,细节处看代码吧。最后答案就是dp[2*n][len][0]
#include<bits/stdc++.h> #include<set> #include<cstdio> #include<iomanip> #include<iostream> #include<string> #include<cstring> #include<algorithm> #define pb push_back #define ll long long #define fi first #define se second #define PI 3.14159265 #define ls l,m,rt<<1 #define rs m+1,r,rt<<1|1 #define eps 1e-7 #define pii pair<int,int> typedef unsigned long long ull; const int inf=1e9+1; const int mod=1e9+7; const int maxn=2e5+10; using namespace std; int n,nxt[250],f[250],dp[205][205][250]; char s[maxn]; void getnxt() { int j, k; j = 0; k = -1; nxt[0] = -1; int tlen=strlen(s); while(j < tlen) if(k == -1 || s[j] == s[k]) nxt[++j] = ++k; else k = nxt[k]; f[0]=0; for(int i=1;i<tlen;i++) { int j=nxt[i]; while(j>=0&&s[j]==s[i])j=nxt[j]; if(j<0)f[i]=0; else if(j>=0&&s[j]!=s[i])f[i]=j+1; else f[i]=0; } } void add(int &x,int y) { x+=y; if(x>=mod)x-=mod; if(x<0)x+=mod; } int main() { scanf("%d %s",&n,s); int len=strlen(s); dp[0][0][0]=1; getnxt(); for(int i=0;i<2*n;i++) { for(int j=0;j<len;j++) { for(int k=0;k<=n;k++) { if(s[j]=='(') { add(dp[i+1][j+1][k+1],dp[i][j][k]); } else add(dp[i+1][f[j]][k+1],dp[i][j][k]); if(k) { if(s[j]==')')add(dp[i+1][j+1][k-1],dp[i][j][k]); else add(dp[i+1][f[j]][k-1],dp[i][j][k]); } } } for(int k=0;k<=n;k++) { add(dp[i+1][len][k+1],dp[i][len][k]); if(k)add(dp[i+1][len][k-1],dp[i][len][k]); } } printf("%d ",dp[2*n][len][0]); return 0; }