• 视频游戏的连击 [USACO12JAN](AC自动机+动态规划)


    传送门

    默认大家都学过trie与AC自动机。

    先求出fail,对于每个节点维护一个sum,sum[u]待表从根到u所形成的字符串能拿到几分。显然sum[u]=sum[fail] + (u是几个字符串的结尾)。

    设dp[i][j]代表长度为i到trie树上的j号节点所得的最大分数,显然有dp[i+1][j的字符k儿子] = max{dp[i+1][j的字符k儿子], dp[i][j] + sum[j的字符k儿子]}

    memset(dp, -1, sizeof(dp));
    dp[0][1] = 0;
    for (int i = 1; i <= k; i++) {
        for (int j = 1; j <= tot; j++) {
            if (dp[i - 1][j] == -1) continue;
            for (int l = 0; l < 26; l++) {
                dp[i][trie[j][l]] = max(dp[i][trie[j][l]], dp[i - 1][j] + sum[trie[j][l]]);
            }
        }
    }

    然后答案就是max{dp[k][i]},i是所有trie树上的节点。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <queue>
    using namespace std;
    int n, k;
    char s[1000];
    int tu[1000][26];
    int trie[1000][26], tot = 1;
    int fail[1000], sum[1000];
    int dp[1010][1000];
    queue<int> q;
    int main() {
        scanf("%d%d", &n, &k);
        for (int i = 1, len; i <= n; i++) {
            scanf("%s", s + 1);
            len = strlen(s + 1);
            int p = 1;
            for (int j = 1; j <= len; j++) {
                int m = s[j] - 'A';
                if (!trie[p][m]) trie[p][m] = ++tot;
                p = trie[p][m];
            }
            sum[p]++;
        }
        for (int i = 0; i < 26; i++) trie[0][i] = 1;
        fail[1] = 0;
        q.push(1);
        while (!q.empty()) {
            int p = q.front(); q.pop();
            for (int i = 0; i < 26; i++) {
                if (trie[p][i]) {
                    fail[trie[p][i]] = trie[fail[p]][i];
                    sum[trie[p][i]] += sum[fail[trie[p][i]]];
                    q.push(trie[p][i]);
                } else {
                    trie[p][i] = trie[fail[p]][i];
                }
            }
        }
        memset(dp, -1, sizeof(dp));
        dp[0][1] = 0;
        for (int i = 1; i <= k; i++) {
            for (int j = 1; j <= tot; j++) {
                if (dp[i - 1][j] == -1) continue;
                for (int l = 0; l < 26; l++) {
                    dp[i][trie[j][l]] = max(dp[i][trie[j][l]], dp[i - 1][j] + sum[trie[j][l]]);
                }
            }
        }
        int ans = -1;
        for (int i = 1; i <= tot; i++) {
            ans = max(ans, dp[k][i]);
        }
        cout << ans;
        return 0;
    }
  • 相关阅读:
    RAID实战案例
    文件系统常用工具实战篇
    挂载文件系统
    硬盘结构类型概述
    创建文件系统实战篇
    JumpServer的会话管理及命令过滤器应用案例
    JumpServer的权限管理
    JumpServer的用户管理
    helm基础
    hpa控制器
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12339695.html
Copyright © 2020-2023  润新知