题目不难想到要应用 DP,建好 AC自动机之后
dp[i][j] 表示到第 i 个字符标号为 j 的节点时最大的连击数是多少
dp 方程也不难想
由于本人实力欠缺,dp 数组的初始化为什么要设为 -1 没想明白,先给自己挖个坑 QAQ
const int N=300+5;
int n,m;
int i,j,k;
char s[N];
int t[N][3],tot=0;
int vis[N],f[N];
int dp[(int)1e3+5][N];
int idx(char ch){ return ch-'A'; }
void insert(char *s)
{
int rt=0;
for(int i=0;s[i];i++){
int x=idx(s[i]);
if(!t[rt][x]) t[rt][x]=++tot;
rt=t[rt][x];
}
vis[rt]++;
}
void getfail()
{
int rt=0;
queue<int> q;
for(int i=0;i<3;i++) if(t[rt][i]) q.push(t[rt][i]);
while(q.size()){
rt=q.front(); q.pop();
for(int i=0;i<3;i++){
if(t[rt][i]) f[t[rt][i]]=t[f[rt]][i],q.push(t[rt][i]);
else t[rt][i]=t[f[rt]][i];
}
vis[rt]+=vis[f[rt]]; // 走到 rt 之后,询问后缀是否也为组合技
}
}
void query(char *s)
{
for(int i=0;i<=m;i++){
for(int j=0;j<=tot;j++) dp[i][j]=-inf;
}
dp[0][0]=0;
for(int i=1;i<=m;i++){
for(int j=0;j<=tot;j++){
for(int k=0;k<3;k++){
dp[i][t[j][k]]=max(dp[i][t[j][k]],dp[i-1][j]+vis[t[j][k]]); //利用父亲更新儿子
}
}
}
}
int main()
{
//IOS;
while(sdd(n,m)){
for(int i=1;i<=n;i++) ss(s),insert(s);
getfail();
query(s);
int ans=0;
for(int i=0;i<=tot;i++) ans=max(ans,dp[m][i]);
pd(ans);
break;
}
return 0;
}