前置知识
解法
多模式串匹配考虑 AC 自动机。
令 \(f_{i,j}\) 表示前 \(i\) 个字符,当前运行到 AC 自动机的状态 \(j\) 时的最大得分。状态转移方程为 \(f_{i,k}=\max\limits_{k \in Son(j)} \{ f_{i-1,j}+sum_{k} \}\),其中 \(sum_{k}\) 表示 fail 树上以 \(k\) 结尾的字符串个数。
最终,有 \(\max\limits_{i=0}^{tot} \{ f_{m,i} \}\) 即为所求。
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define sort stable_sort
#define endl '\n'
int trie[1000][5],fail[1000],sum[1000],f[2000][1000],tot=0;
char s[1000];
int val(char x)
{
return x-'A'+1;
}
void insert(char s[],int len)
{
int x=0,i;
for(i=1;i<=len;i++)
{
if(trie[x][val(s[i])]==0)
{
tot++;
trie[x][val(s[i])]=tot;
}
x=trie[x][val(s[i])];
}
sum[x]++;
}
void build()
{
int x,i;
queue<int>q;
for(i=1;i<=3;i++)
{
if(trie[0][i]!=0)
{
fail[trie[0][i]]=0;
q.push(trie[0][i]);
}
}
while(q.empty()==0)
{
x=q.front();
q.pop();
for(i=1;i<=3;i++)
{
if(trie[x][i]==0)
{
trie[x][i]=trie[fail[x]][i];
}
else
{
fail[trie[x][i]]=trie[fail[x]][i];
sum[trie[x][i]]+=sum[fail[trie[x][i]]];
q.push(trie[x][i]);
}
}
}
}
int main()
{
int n,m,ans=0,i,j,k;
cin>>n>>m;
memset(f,-0x3f,sizeof(f));
for(i=1;i<=n;i++)
{
cin>>(s+1);
insert(s,strlen(s+1));
}
build();
f[0][0]=0;
for(i=1;i<=m;i++)
{
for(j=0;j<=tot;j++)
{
if(f[i-1][j]>=0)
{
for(k=1;k<=3;k++)
{
f[i][trie[j][k]]=max(f[i][trie[j][k]],f[i-1][j]+sum[trie[j][k]]);
}
}
}
}
for(i=0;i<=tot;i++)
{
ans=max(ans,f[m][i]);
}
cout<<ans<<endl;
return 0;
}
后记
多倍经验:luogu P3041 [USACO12JAN] Video Game G
标签:combos,int,题解,sum,long,char,game,define,1000 From: https://www.cnblogs.com/The-Shadow-Dragon/p/18378676