分析
我们考虑 上的 ,定义 为,匹配了 个字符,当前在 节点的最大价值。那么转移为 那么,现在的问题就在于如何求出 数组。由于 指针指向的是最长后缀,所以有 的转移,这个可以在构造 指针时就构造好。那么总的复杂度为 。
代码
#include<bits/stdc++.h> using namespace std; const int N = 1e3 + 100; int f[N][N],fail[N],ch[N][3],val[N],size; int n,m; void insert(char *S) { int len = strlen(S + 1),u = 0; for(int i = 1;i <= len;i++) { int c = (S[i] - 'A'); if(!ch[u][c]) ch[u][c] = ++size; u = ch[u][c]; }val[u]++; } void build() { queue<int> Q; for(int i = 0;i < 3;i++) if(ch[0][i]) Q.push(ch[0][i]); while(!Q.empty()) { int x = Q.front();Q.pop(); for(int i = 0;i < 3;i++) { int y = ch[x][i]; if(y) {fail[ch[x][i]] = ch[fail[x]][i];val[y] += val[fail[y]];Q.push(y);} else ch[x][i] = ch[fail[x]][i]; } } } int main() { scanf("%d%d",&n,&m); for(int i = 1;i <= n;i++) { static char S[N];scanf("%s",S + 1);insert(S); } build();memset(f,-0x3f,sizeof(f)); for(int i = 0;i < 3;i++) f[1][ch[0][i]] = val[ch[0][i]]; // for(int i = 1;i <= size;i++) cout << val[i] << endl; for(int i = 2;i <= m;i++) { for(int j = 1;j <= size;j++) { for(int k = 0;k < 3;k++) { f[i][ch[j][k]] = max(f[i][ch[j][k]],f[i-1][j] + val[ch[j][k]]); } } } int ans = 0; for(int i = 1;i <= size;i++) ans = max(ans,f[m][i]); cout << ans << endl;return 0; }