SPOJ VIDEO Video game combos 题解
SP10502 VIDEO - Video game combos
AC 自动机上的动态规划。
由题目中这句话,不难想到 AC 自动机:
在 中出现一次指的是 是 从某个位置起的连续子串。如果 从 的多个位置起都是连续子串,那么算作 出现了多次。
考虑到每个位置有多种转移情况,且满足最优子结构性质,使用动态规划。观察后发现确定一个位置需要两个参数:目前是主串的的 个字符,目前在 AC 自动机中的位置 。易得转移方程:
这里 是枚举 AC 自动机中的出边, 表示在 AC 自动机中的位置 匹配可以得到的分数。实质上,这是一个根据现在的状态推出后面状态的方程,所以 里会有 这一项,而后面一项则是目前枚举的状态转移之后的得分。
这里把 预处理出来了,实际上不预处理应该也是可以的。
注意状态需要初始化为负无穷,很明显是不能从不可能的状态转移的。
#include <bits/stdc++.h>
using namespace std;
int n,k,ans,trie[310][3],ap[310],fail[310],que[310],f[1010][310],h[310],cnt=0;
char str[310];
void insert(char str[])
{
int l=strlen(str),root=0;
for(int i=0;i<l;i++)
{
int id=str[i]-'A';
if(!trie[root][id])trie[root][id]=++cnt;
root=trie[root][id];
}
ap[root]++;
}
void build_ac()
{
int head=0,tail=0;
fail[0]=0;
for(int i=0;i<3;i++)
if(trie[0][i])que[tail++]=trie[0][i];
while(head<tail)
{
int now=que[head];
for(int i=0;i<3;i++)
if(trie[now][i])fail[trie[now][i]]=trie[fail[now]][i],que[tail++]=trie[now][i];
else trie[now][i]=trie[fail[now]][i];
head++;
}
}
int main()
{
scanf("%d%d",&n,&k);
for(int i=0;i<n;i++)
{
scanf("%s",str);
insert(str);
}
build_ac();
for(int i=0;i<=cnt;i++)
for(int j=i;j!=0;j=fail[j])h[i]+=ap[j];
for(int i=0;i<=k;i++)
for(int j=0;j<=cnt;j++)
f[i][j]=-99999999;
f[0][0]=0;
for(int i=0;i<k;i++)
for(int j=0;j<=cnt;j++)
for(int k=0;k<3;k++)
f[i+1][trie[j][k]]=max(f[i+1][trie[j][k]],f[i][j]+h[trie[j][k]]);
for(int i=0;i<=cnt;i++)
ans=max(ans,f[k][i]);
printf("%d",ans);
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探