zoukankan      html  css  js  c++  java
  • 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
    ", 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
    ", 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;
    }
    
    
  • 相关阅读:
    安全传输平台项目扩展——keymngserver重构-硬件扩展
    安全传输平台项目扩展——C复习-C++复习-keymngclient重构
    安全传输平台项目——客户端代码移植-项目模块总结
    安全传输平台项目——配置管理终端-读写数据库
    根号分治刷题记录
    使用netsh命令来管理IP安全策略
    关于make_shared无法访问非公有构造函数的解决方法
    两两交换链表中的节点-递归解法
    Spring 的 AOP 简介
    Spring IOC和DI 注解开发
  • 原文地址:https://www.cnblogs.com/RUSH-D-CAT/p/9399175.html
Copyright © 2011-2022 走看看