1、给出只包含‘(‘,‘)‘,‘[‘,‘]‘的字符串$s$,删除一些字符,使得剩下的是合法的括号。有多少种删除方法? $|s|\leq 40$
思路:左括号和右括号较少的一种不会大于20。假设左括号少。设$f[i][mask][k]$表示处理了前$i$个字符,其中留下的字符以$k$开头($k=0$表示‘(‘,$k=1$表示‘[‘),且所有留下的字符状态为$mask$,($mask$的最高位为1,其他位为0表示另一种括号,否则表示跟最高位相同的符号)。
#include <stdio.h> #include <string.h> #include <string> #include <iostream> #include <vector> #include <set> #include <map> #include <queue> #include <algorithm> #include <stack> using namespace std; long long f[2][1<<20][2]; class BracketSequenceDiv1 { public: long long count(string s) { const int n=(int)s.size(); int L=0,R=0; for(int i=0;i<n;++i) { if(s[i]==‘(‘||s[i]==‘[‘) ++L; else ++R; } if(L>R) { reverse(s.begin(),s.end()); for(int i=0;i<n;++i) { if(s[i]==‘(‘) s[i]=‘)‘; else if(s[i]==‘)‘) s[i]=‘(‘; else if(s[i]==‘[‘) s[i]=‘]‘; else s[i]=‘[‘; } swap(L,R); } int pre=0,cur=1; memset(f[pre],0,sizeof(f[pre])); f[0][0][0]=1; for(int i=1;i<=n;++i) { char c=s[i-1]; memset(f[cur],0,sizeof(f[cur])); for(int j=0;j<(1<<L);++j) for(int k=0;k<2;++k) if(f[pre][j][k]) { long long p=f[pre][j][k]; f[cur][j][k]+=p; if(c==‘(‘) { if(j==0) f[cur][1][0]+=p; else f[cur][j<<1|(!k)][k]+=p; } else if(c==‘[‘) { if(j==0) f[cur][1][1]+=p; else f[cur][j<<1|k][k]+=p; } else if(c==‘)‘) { if(j!=0&&(k^(j&1))) f[cur][j>>1][k]+=p; } else { if(j!=0&&(0==(k^(j&1)))) f[cur][j>>1][k]+=p; } } pre^=1; cur^=1; } return f[pre][0][0]+f[pre][0][1]-1; } };
时间: 2024-12-29 15:51:08