CF1015F Bracket Substring (KMP+DP)

题目大意:给你一个长度为$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\n",f[2*n][0][len][1]);
60     return 0;
61 }

 

posted @ 2018-11-02 15:17  guapisolo  阅读(222)  评论(0)    收藏  举报