Codeforces Round #501 (Div. 3) F: Bracket Substring
一开始根本没想去重的事(T▽T)写了个辣鸡,然后样例纷纷苟住了。
当时感到非常自豪.....
dp[len][prefix][pos][0/1]
: 前len
位,左括号比右括号多prefix
,与串s
匹配到了第pos
个位置,在len-1
之前有没有完全匹配串s
的方案数。
关于状态转移,如果匹配上了,pos
转移到pos+1
,如果没匹配上,那就施展Fail指针。
不过这么做很沙比的啊。
#include <iostream>
#include <cstring>
using namespace std;
const int MOD = 1e9+7;
const int N = 202;
int n,dp[N][N][N][2];
char s[N]; int slen;
int fail[N][2],nex[N];
void getFail() {
int j=0;
nex[0] = nex[1] = 0;
for(int i=1;i<slen;i++) {
while(j>0 && s[i]!=s[j]) j=nex[j];
if(s[i]==s[j]) j++;
nex[i+1] = j;
}
if (s[0] == '(') fail[0][0] = 1;
if (s[0] == ')') fail[0][1] = 1;
for(int i=1;i<=slen;i++) {
int pos=i;
while(pos && s[pos]!='(') pos=nex[pos];
fail[i][0] = pos+1;
if(pos==0&&s[0]==')') fail[i][0]=0;
pos = i;
while(pos && s[pos]!=')') pos=nex[pos];
fail[i][1] = pos+1;
if(pos==0&&s[0]=='(') fail[i][1]=0;
}
}
int main() {
scanf("%d%s", &n, s);
slen = strlen(s);
getFail();
dp[0][0][0][0]=1;
for(int i=0;i<2*n;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<=slen;k++){
for(int state=0;state<2;state++)
if(s[k]=='(')
{
(dp[i+1][j+1][k+1][state] += dp[i][j][k][state]) %= MOD;
if(j) (dp[i+1][j-1][fail[k][1]][state] += dp[i][j][k][state]) %= MOD;
} else
if(s[k]==')')
{
(dp[i+1][j+1][fail[k][0]][state] += dp[i][j][k][state]) %= MOD;
if(j) (dp[i+1][j-1][k+1][state] += dp[i][j][k][state]) %= MOD;
} else if(state == 1) {
(dp[i+1][j+1][fail[k][0]][1] += dp[i][j][k][0]) %= MOD;
if(j) (dp[i+1][j-1][fail[k][1]][1] += dp[i][j][k][0]) %= MOD;
(dp[i+1][j+1][fail[k][0]][1] += dp[i][j][k][1]) %= MOD;
if(j) (dp[i+1][j-1][fail[k][1]][1] += dp[i][j][k][1]) %= MOD;
}
}
}
}
int ans=0;
for(int i=0;i<=slen;i++){
(ans += dp[2*n][0][i][1]) %= MOD;
}
(ans += dp[2*n][0][slen][0]) %= MOD;
cout<<ans<<endl;
}
不妨这么来设计状态。
当pos < strlen(s)
dp[len][prefix][pos]
: 前len
位,左括号比右括号多prefix
,与串s
匹配到了第pos
个位置的方案数。
当pos = strlen(s)
dp[len][prefix][pos]
: 前len
位,左括号比右括号多prefix
,存在和s
相等的子串的方案数。
转移会舒适一点。
#include <iostream>
#include <cstring>
using namespace std;
const int MOD = 1e9+7;
const int N = 202;
int n,dp[N][N][N];
char s[N]; int slen;
int fail[N][2],nex[N];
void getFail() {
int j=0;
nex[0] = nex[1] = 0;
for(int i=1;i<slen;i++) {
while(j>0 && s[i]!=s[j]) j=nex[j];
if(s[i]==s[j]) j++;
nex[i+1] = j;
}
//printf("len = %d\n", slen);
if (s[0] == '(') fail[0][0] = 1;
if (s[0] == ')') fail[0][1] = 1;
for(int i=1;i<=slen;i++) {
int pos=i;
while(pos && s[pos]!='(') pos=nex[pos];
fail[i][0] = pos+1;
if(pos==0&&s[0]==')') fail[i][0]=0;
pos = i;
while(pos && s[pos]!=')') pos=nex[pos];
fail[i][1] = pos+1;
if(pos==0&&s[0]=='(') fail[i][1]=0;
//printf("i=%d %d %d\n", i,fail[i][0],fail[i][1]);
}
}
int main() {
scanf("%d%s", &n, s);
slen = strlen(s);
getFail();
dp[0][0][0]=1;
for(int i=0;i<2*n;i++){
for(int j=0;j<=n;j++){
for(int k=0;k<slen;k++){
if(s[k]=='(')
{
(dp[i+1][j+1][k+1] += dp[i][j][k]) %= MOD;
if(j) (dp[i+1][j-1][fail[k][1]] += dp[i][j][k]) %= MOD;
} else
if(s[k]==')')
{
(dp[i+1][j+1][fail[k][0]] += dp[i][j][k]) %= MOD;
if(j) (dp[i+1][j-1][k+1] += dp[i][j][k]) %= MOD;
}
}
(dp[i+1][j+1][slen] += dp[i][j][slen]) %= MOD;
if(j) (dp[i+1][j-1][slen] += dp[i][j][slen]) %= MOD;
}
}
int ans=dp[2*n][0][slen];
cout<<ans<<endl;
}