题目大意:给你一个长度为$n$的括号序列$T$,要求你构造一个长度为$2n$的括号序列$S$,保证这个括号序列在插入数字后一定是正确的,并且$T$是$S$的一个子串
还以为是什么纯粹的数学构造题,一通乱搞无果。好吧,并没有想到$KMP$....
题解:首先用$KMP$预处理出数组$to[i][0/1]$,表示在$i+1$位填上括号$'('$和$')'$后匹配到字符串T的位置
定义$f[i][j][k][0/1]$表示已经添加了$i$个括号,左右括号数量之差是$j$,已经匹配到了字符串$T$的第$k$位,是否包含$T$串
再用$DP$转移即可,实现很简单
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N 205 6 #define maxn 250 7 #define uint unsigned int 8 #define ll long long 9 #define mod 1000000007 10 using namespace std; 11 12 int n,len; 13 char str[N]; 14 uint f[N][N][N][2]; 15 int nxt[N],to[N][2]; 16 void get_nxt() 17 { 18 int i=1,j=0;nxt[1]=0; 19 while(i<=len){ 20 if(j==0||str[i]==str[j]){ 21 i++,j++;nxt[i]=j; 22 }else{j=nxt[j];} 23 } 24 for(int i=0,k;i<len;i++) 25 { 26 k=i; 27 if(str[i+1]=='('){ 28 to[i][0]=k+1;k=k+1; 29 for(;str[k]!=')'&&k;k=nxt[k]); 30 to[i][1]=k; 31 }else{ 32 to[i][1]=k+1;k=k+1; 33 for(;str[k]!='('&&k;k=nxt[k]); 34 to[i][0]=k; 35 } 36 } 37 } 38 39 int main() 40 { 41 scanf("%d",&n); 42 scanf("%s",str+1); 43 len=strlen(str+1); 44 get_nxt(); 45 f[0][0][0][0]=1; 46 for(int i=0;i<2*n;i++) 47 { 48 for(int j=0;j<=n;j++){ 49 for(int k=0;k<len;k++) 50 { 51 if(j<n)(f[i+1][j+1][to[k][0]][to[k][0]==len]+=f[i][j][k][0])%=mod; //'(' 52 if(j>0)(f[i+1][j-1][to[k][1]][to[k][1]==len]+=f[i][j][k][0])%=mod; //')' 53 } 54 if(j<n)(f[i+1][j+1][len][1]+=f[i][j][len][1])%=mod; 55 if(j>0)(f[i+1][j-1][len][1]+=f[i][j][len][1])%=mod; 56 } 57 } 58 int num=0; 59 printf("%u ",f[2*n][0][len][1]); 60 return 0; 61 }