视频游戏的连击 [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;
}

原文地址:https://www.cnblogs.com/zcr-blog/p/12339695.html

时间: 2024-07-31 00:13:30

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

P3041 [USACO12JAN]视频游戏的连击Video Game Combos

P3041 [USACO12JAN]视频游戏的连击Video Game Combos https://www.luogu.org/problemnew/show/P3041 分析: AC自动机. 建立AC自动机,然后dp[i][j]表示经过了i个字符,到达自动机上j这个位置,的得分. 那么dp[i-1][j] + val[ch[j][k]] -> dp[i][ch[j][k]]. 表示从j点,往前走一步,加上新加一个字符产生的贡献. 代码: 1 #include<bits/stdc++.h&g

[USACO12JAN]视频游戏的连击Video Game Combos(AC自动机+DP)

Description 贝西正在打格斗游戏.游戏里只有三个按键,分别是“A”.“B”和“C”.游戏中有 N 种连击 模式,第 i 种连击模式以字符串 Si 表示,只要贝西的按键中出现了这个字符串,就算触发了一次连 击模式.不 同的连击模式是独立计算的,如果几个连击模式同时出现在贝西的按键顺序里,就算有重 叠部分, 也可以同时算作触发了多个模式. 假如有三个连击模式,分别是“AB”,“BA”,“ABC”,而贝西按下了“ABABC”,那么她一共 触发了四次 连击.假设贝西一共可以按 K 次键,那么她

【BZOJ1030】[JSOI2007]文本生成器 AC自动机+动态规划

[BZOJ1030][JSOI2007]文本生成器 Description JSOI交给队员ZYX一个任务,编制一个称之为"文本生成器"的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章-- 也就是说,生成的文章中每个字节都是完全随机的.如果一篇文章中至少包含使用者们了解的一个单词,那么我们说这篇文章是可读的(我们称文章a包含单词b,当且仅当单词b是文章a的子串).但是,即使按照这样的标准

[JSOI2007][BZOJ1030] 文本生成器|AC自动机|动态规划

1030: [JSOI2007]文本生成器 Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 2609  Solved: 1074[Submit][Status][Discuss] Description JSOI交给队员ZYX一个任务,编制一个称之为“文本生成器”的电脑软件:该软件的使用者是一些低幼人群,他们现在使用的是GW文本生成器v6版.该软件可以随机生成一些文章―――总是生成一篇长度固定且完全随机的文章—— 也就是说,生成的文章中每个字节都是完

tyvj P1519 博彩游戏(AC自动机+DP滚动数组)

P1519 博彩游戏 背景 Bob最近迷上了一个博彩游戏…… 描述 这个游戏的规则是这样的:每花一块钱可以得到一个随机数R,花上N块钱就可以得到一个随机序列:有M个序列,如果某个序列是产生的随机序列的子串,那么就中奖了,否则不中.Bob会告诉你这M个序列,和身上有的钱的总数N,当然还有R的范围.请你告诉Bob中奖的概率有多少? 输入格式 第一行三个用空格隔开的数N.M和R的范围R.其中1<=R<=9,0<N<=60,0<M<=20000.下面M行每行一个字符串(长度小于

【BZOJ1444】[Jsoi2009]有趣的游戏 AC自动机+概率DP+矩阵乘法

[BZOJ1444][Jsoi2009]有趣的游戏 Description Input 注意 是0<=P Output Sample Input Sample Output HINT  30%的数据保证, n ≤ 2. 50%的数据保证, n ≤ 5. 100%的数据保证, n , l, m≤ 10. 题解:本题的做法真的很多啊,概率DP,期望DP,当然还有矩乘黑科技~ 就是先跑AC自动机,弄出转移矩阵,然后自乘50次就行了. #include <cstdio> #include <

bzoj1444 有趣的游戏(AC自动机+概率dp)

题意: 给定n个长度为l的模式串,现在要用前m个大写字母生成一个随机串,每个字符有自己的出现几率,第一次出现的字符串获胜,求最终每个字符串的获胜几率. 分析: 容易想到先把所有的字符串建成一个AC自动机 然后对于生成的随机串就相当于从AC自动机的root开始在自动机上走,然后求走到每个单词节点的概率 因为这是存在环的,不是DAG图,所以不能直接DP 考虑构造出刚开始的转移矩阵,然后对转移矩阵作矩阵乘法不断迭代就能得到正确答案了 转移矩阵如何建呢? 1)a[i][ch[i][j]]+=p[j] (

UVA_11468_Substring_(AC自动机+概率动态规划)

描述 https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2463 给出一些子串.然后给出一些字符,以及每个字符出现的概率.现在用这些字符组成一个长度为s的字符串,问之前给出的子串都没有在这个字符串中出现的概率是多少. 分析 边选字母边匹配.只要前面的字串都不能匹配成功即可.用前面的那些子串造出个AC自动机,然后在上面跑.用match数组表示每

BZOJ 1212 HNOI2004 L语言 AC自动机(Trie树)+动态规划

题目大意:给定一个单词表和m个字符串 问每个字符串的最长的前缀,满足这个前缀可以拆分成一些字符串 使这些字符串都在单词表中出现过 再也不敢看错数据范围了--一道明明用Trie树能解决的问题居然被我写了AC自动机-- 将单词表中的单词全都插入AC自动机 每个单词所在的节点记录这个单词的长度 然后对于每个字符串 用f[i]表示长度为i的前缀是否能拆分成单词表中的单词 跑AC自动机 对于每个匹配的节点 从这个节点开始到根的fail路径上的所有len f[i]|=f[i-len] 找到最大的为1的f[i