1. 程式人生 > >CF1015F Bracket Substring(dp+Trie圖)

CF1015F Bracket Substring(dp+Trie圖)

用所有合法序列的方案數減不包含題目中要求的子序列的合法序列數

後者用AC自動機維護一下dp就好

 1 #include<queue>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define mod 1000000007
 6 using namespace std;
 7 int n,m,cnt,tot,minu,ans;
 8 char son[205];
 9 int al[205][105];
10 int dp[205][205][105];
11
int ed[205]; 12 int tr[205][2]; 13 int fail[205]; 14 void build(char b[]){ 15 int now=0; 16 int len=strlen(b+1); 17 for(int i=1;i<=len;i++){ 18 int k=-1; 19 if(b[i]=='(')k=1; 20 else k=0; 21 if(!tr[now][k])tr[now][k]=++cnt; 22 now=tr[now][k];
23 } 24 ed[now]=1; 25 } 26 void getfail(){ 27 queue<int>que; 28 int now=0; 29 if(tr[0][0])que.push(tr[0][0]); 30 if(tr[0][1])que.push(tr[0][1]); 31 while(!que.empty()){ 32 int s=que.front(); 33 que.pop(); 34 if(tr[s][0]){ 35 fail[tr[s][0
]]=tr[fail[s]][0]; 36 que.push(tr[s][0]); 37 }else{ 38 tr[s][0]=tr[fail[s]][0]; 39 } 40 if(tr[s][1]){ 41 fail[tr[s][1]]=tr[fail[s]][1]; 42 que.push(tr[s][1]); 43 }else{ 44 tr[s][1]=tr[fail[s]][1]; 45 } 46 } 47 } 48 int main(){ 49 scanf("%d",&n); 50 scanf("%s",son+1); 51 build(son); 52 getfail(); 53 al[1][1]=1; 54 for(int i=2;i<=2*n;i++){ 55 for(int j=0;j<=n;j++){ 56 (al[i][j]+=al[i-1][j+1])%=mod; 57 if(j)(al[i][j]+=al[i-1][j-1])%=mod; 58 } 59 } 60 tot=al[2*n][0]; 61 dp[0][0][0]=1; 62 for(int i=1;i<=2*n;i++){ 63 for(int j=0;j<=cnt;j++){ 64 for(int k=0;k<=n;k++){ 65 if(!ed[tr[j][0]]){ 66 (dp[i][tr[j][0]][k]+=dp[i-1][j][k+1])%=mod; 67 } 68 if(!ed[tr[j][1]]&&k){ 69 (dp[i][tr[j][1]][k]+=dp[i-1][j][k-1])%=mod; 70 } 71 } 72 } 73 } 74 for(int i=0;i<cnt;i++){ 75 (minu+=dp[2*n][i][0])%=mod; 76 } 77 ans=((tot-minu)%mod+mod)%mod; 78 printf("%d\n",ans); 79 return 0; 80 }