挺明显的dp,设f[i][j]表示走到第i个位置,trie上的第j个节点的最大答案,把每个结尾+1然后求出前缀和,直接更新就可以了
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
#define inf 0xc3c3c3c3
using namespace std;
const int N=1e5+5;
int ch[N][5];
char s[N];
int tag[N],cnt=1;
int fail[N],q[N];
int f[1005][500];
int num[N];
int n,K;
inline void add(int x,int k)
{
memset(ch[cnt],0,sizeof(ch[cnt]));
num[cnt]=0;
ch[x][k]=cnt++;
}
inline void ins()
{
int n=strlen(s);
int x=0;
fo(i,0,n-1)
{
int c=s[i]-'A';
if (!ch[x][c])add(x,c);
x=ch[x][c];
}
num[x]++;
}
inline void acmach()
{
int w=1;
int x;
q[0]=0;
fo(i,0,w-1)
{
x=q[i];
num[x]+=num[fail[x]];
fo(j,0,2)
if (ch[x][j])
{
q[w++]=ch[x][j];
if (!x)fail[ch[x][j]]=0;
else fail[ch[x][j]]=ch[fail[x]][j];
}
else ch[x][j]=ch[fail[x]][j];
}
}
inline void dp()
{
memset(f,0xc3,sizeof(f));
f[0][0]=0;
fo(i,0,K-1)
fo(j,0,cnt-1)
if (f[i][j]!=inf)
fo(k,0,2)
{
int x=ch[j][k];
f[i+1][x]=max(f[i+1][x],f[i][j]+num[x]);
}//f[i][ch[j][k]]=max(f[i][ch[j][k]],f[i-1][j]+num[ch[j][k]]);
}
int main()
{
scanf("%d%d",&n,&K);
num[0]=0;
memset(ch[0],0,sizeof(ch[0]));
cnt=1;
fo(i,1,n)
{
scanf("%s",s);
ins();
}
acmach();
dp();
int ans=0;
fo(i,0,cnt-1)ans=max(ans,f[K][i]);
printf("%d\n",ans);
}
版权声明:本文为qq_35866453原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。