一、题目
二、解法
又是一道 自动机上 的题,随手乱切。
设 为长度为 ,在自动机上匹配到 点的最大值,一开始全赋最小值,在 树上求一个链的前缀和,直接转移即可,时间复杂度 ,贴个代码。
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
const int M = 305;
int read()
{
int x=0,flag=1;
char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,ans,f[1005][M];
char s[M];
struct Automaton
{
int c[M][26],val[M],fail[M],cnt;
void ins(char *s)
{
int len=strlen(s),now=0;
for(int i=0; i<len; i++)
{
int v=s[i]-'A';
if(!c[now][v]) c[now][v]=++cnt;
now=c[now][v];
}
val[now]++;
}
void build()
{
queue<int> q;
for(int i=0; i<26; i++) if(c[0][i]) q.push(c[0][i]);
while(!q.empty())
{
int t=q.front();
q.pop();
for(int i=0; i<26; i++)
if(c[t][i])
{
fail[c[t][i]]=c[fail[t]][i];
val[c[t][i]]+=val[fail[c[t][i]]];
q.push(c[t][i]);
}
else c[t][i]=c[fail[t]][i];
}
}
void dp()
{
memset(f,-0x3f,sizeof f);
f[0][0]=0;
for(int i=0; i<m; i++)
{
for(int j=0; j<=cnt; j++)
{
for(int k=0; k<3; k++)
{
f[i+1][c[j][k]]=max(f[i+1][c[j][k]],f[i][j]+val[c[j][k]]);
}
}
}
for(int j=0; j<=cnt; j++)
ans=max(ans,f[m][j]);
printf("%d\n",ans);
}
} AC;
int main()
{
n=read();
m=read();
for(int i=1; i<=n; i++)
{
scanf("%s",s);
AC.ins(s);
}
AC.build();
AC.dp();
}