洛谷传送门
BZOJ传送门
题目描述
贝西在玩一款游戏,该游戏只有三个技能键 “A”“B”“C” “ A ” “ B ” “ C ” 可用,但这些键可用形成 N N 种()特定的组合技。第 i i 个组合技用一个长度为到 15 15 的字符串 Si S i 表示。
当贝西输入的一个字符序列和一个组合技匹配的时候,他将获得 1 1 分。特殊的,他输入的一个字符序列有可能同时和若干个组合技匹配,比如时, 3 3 种组合技分别为””, “ CB C B ”, 和” ABACB A B A C B ”,若贝西输入” ABACB A B A C B ”,他将获得 3 3 分。
若贝西输入恰好 ( 1≤K≤1,000 1 ≤ K ≤ 1 , 000 )个字符,他最多能获得多少分?
输入输出格式
输入格式
第一行两个正整数, 表示 N、K N 、 K 。
接下来 N N 行, 每行一个由构成的字符串, 表示一个组合技的序列。
输出格式
一行一个正整数, 表示最多能获得的分数。
输入输出样例
输入样例#1:
3 7
ABA
CB
ABACB
输出样例#1:
4
解题分析
AC A C 自动机上 DP D P 的套路题。
先建出 AC A C 自动机, 构出 trie t r i e 树, 在每个合法字符串的末端打上标记。
注意一个大串可能包含多个合法小串, 所以将每个合法的 fail f a i l 转移的答案累加到当前点(跳 fail f a i l 后得到的是一个合法后缀, 而转移是通过前缀转移, 不会重复。)。
然后 dp[i][j] d p [ i ] [ j ] 表示第 i i 位, 当前在树上第 j j 个节点的答案,通过三个字符的转移取即可。
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <algorithm>
#include <queue>
#define R register
#define IN inline
#define gc getchar()
#define W while
#define MX 100500
#define INF 100000000
int num, k, cnt, root, ans;
char buf[21];
int to[MX][3], ct[MX], fail[MX], dp[1050][350];
std::queue <int> q;
namespace AC
{
void insert(char* str, R int len)
{
R int now = root;
for (R int i = 0; i < len; ++i)
{
if(!to[now][str[i] - 'A']) to[now][str[i] - 'A'] = ++cnt;
now = to[now][str[i] - 'A'];
}
ct[now]++;
}
void build()
{
R int now;
for (R int i = 0; i < 3; ++i)
if(to[root][i]) q.push(to[root][i]);
W (!q.empty())
{
now = q.front(); q.pop();
for (R int i = 0; i < 3; ++i)
{
if(to[now][i])
{
fail[to[now][i]] = to[fail[now]][i];
q.push(to[now][i]);
}
else to[now][i] = to[fail[now]][i];//为了传递fail数组, 得到第一个符合条件的答案
}
ct[now] += ct[fail[now]];
}
}
void DP()
{
R int i, j, o;
for (i = 0; i <= k; ++i)
for (j = 1; j <= cnt; ++j)
dp[i][j] = -INF;
for (i = 1; i <= k; ++i)
for (j = 0; j <= cnt; ++j)
{
for (o = 0; o < 3; ++o)
dp[i][to[j][o]] = std::max(dp[i][to[j][o]], dp[i - 1][j] + ct[to[j][o]]);
}
for (R int i = 0; i <= cnt; ++i) ans = std::max(ans, dp[k][i]);
}
}
int main(void)
{
scanf("%d%d", &num, &k);
W (num--) scanf("%s", buf), AC::insert(buf, std::strlen(buf));
AC::build(), AC::DP();
printf("%d", ans);
}