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;
}

posted @ 2018-08-01 03:11  RUSH_D_CAT  阅读(349)  评论(0编辑  收藏  举报