zoukankan      html  css  js  c++  java
  • Codeforces 1015 F- Bracket Substring (DP+kmp预处理)

    题目链接
    思路
    定义题目给定的字符串叫s,长度为2n的字符串叫str。"("表示+1,“)”表示-1,那么可以通过数字大小来表示括号匹配的数量,0为恰好匹配。
    (dp[i][j][k]):匹配到字符串str第i位,括号匹配正负值为j,对应匹配到字符串s第k位的所有方案数。
    (f[i][0]):在字符串s匹配到第i位,第i+1位填")"时,在字符串s中所对应的位置。
    (f[i][1]:)在字符串s匹配到第i位,第i+1位填"("时,在字符串s中所对应的位置。
    f[i][0/1]也相当于求了一下next数组。可以看成当这一位填了"("或")"之后不再是s的子串,那么s的最长前缀和str的最长后缀就要更新一下,就是kmp的道理。

    考虑转移方程,在字符串str中下一位需要填“(”或者")"
    填"("时:(dp[i+1][j+1][f[k][1]]+=dp[i][j][k])
    填")"时:(dp[i+1][j-1][f[k][0]]+=dp[i][j][k](j>0))

    在预处理的过程中会发现设置了(f[len][0]=f[len][1]=len),是因为当整个s串已经匹配完全的时候,那么后面不管怎么加那么在s中所匹配的最长长度都是len。所以在最后的转移中,k一定要枚举到长度为len的情况。
    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef pair<int, int> PII;
    const int N = 200 + 10;
    const int mod = 1e9 + 7;
    
    char s[N];
    int nxt[N], len;
    int dp[N][N][N], f[N][2];
    
    void kmp() {
        len = strlen(s + 1);
        for(int i = 2, j = 0; i <= len; i++) {
            while(j && s[j + 1] != s[i]) j = nxt[j];
            if(s[j + 1] == s[i]) j++;
            nxt[i] = j;
        }
        for(int i = 0; i < len; i++) {
            int p = i, q = i;
            while(p && s[p + 1] != ')') p = nxt[p];
            while(q && s[q + 1] != '(') q = nxt[q];
            if(s[p + 1] == ')') p++;
            if(s[q + 1] == '(') q++;
            f[i][0] = p;
            f[i][1] = q;
        }
        f[len][0] = f[len][1] = len;
    }
    
    void solve() {
        int n, m;
        scanf("%d%s", &n, s + 1);
        m = n * 2;
        kmp();
        dp[0][0][0] = 1;
        for(int i = 0; i < m; i++) {
            for(int j = 0; j <= n; j++) {
                for(int k = 0; k <= len; k++) {
                    dp[i + 1][j + 1][f[k][1]] = (1LL * dp[i + 1][j + 1][f[k][1]] + dp[i][j][k]) % mod;
                    if(j) dp[i + 1][j - 1][f[k][0]] = (1LL * dp[i + 1][j - 1][f[k][0]] + dp[i][j][k]) % mod;
                }
            }
        }
        printf("%d
    ", dp[m][0][len]);
    }
    
    signed main() {
        solve();
        return 0;
    }
    
  • 相关阅读:
    算法笔记_182:历届试题 核桃的数量(Java)
    算法笔记_181:历届试题 回文数字(Java)
    算法笔记_180:历届试题 国王的烦恼(Java)
    算法笔记_179:历届试题 数字游戏(Java)
    算法笔记_178:历届试题 邮局(Java)
    算法笔记_177:历届试题 城市建设(Java)
    算法笔记_176:历届试题 最大子阵(Java)
    算法笔记_175:历届试题 蚂蚁感冒(Java)
    redis集群与分片(2)-Redis Cluster集群的搭建与实践
    redis集群与分片(1)-redis服务器集群、客户端分片
  • 原文地址:https://www.cnblogs.com/ZX-GO/p/14412799.html
Copyright © 2011-2022 走看看