Video Games G:弱智紫题,30min 切了,dp 思路非常板。
多模式串一看肯定就是要建出 AC 自动机,然后在 fail 树里下传标记,预处理每个节点到达后的得分。
然后设计 \(dp_{i,j}\) 表示第 \(i\) 个字符,AC 自动机里匹配节点在 \(j\) 的最大答案,刷表法转移即可:
\[dp_{i+1,ch_{j,c}} \gets \max(dp_{i+1,ch_{j,c}},dp_{i,j}+con_{ch_{j,c}})
\]
时间复杂度 \(O(nk\left|S\right|)\)。
代码
#include <bits/stdc++.h>
#define fi first
#define se second
#define lc (p<<1)
#define rc ((p<<1)|1)
#define eb(x) emplace_back(x)
#define pb(x) push_back(x)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double ldb;
using pi=pair<int,int>;
int n,m;
int ch[305][5],idx=0,ne[305],tot[305],dp[1005][305],ans=0;
char s[20];
vector<int>g[305];
void insert(char *s)
{int p=0;for(int i=1;s[i];i++){int c=s[i]-'A';if(ch[p][c]==0)ch[p][c]=++idx;p=ch[p][c];}tot[p]++;
}
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 u=q.front();q.pop();for(int i=0;i<3;i++){int v=ch[u][i];if(v)ne[v]=ch[ne[u]][i],q.push(v);else ch[u][i]=ch[ne[u]][i];}}
}
void dfs1(int u)
{for(auto v:g[u]){tot[v]+=tot[u];dfs1(v);}
}
void init()
{for(int i=1;i<=idx;i++)g[ne[i]].push_back(i);dfs1(0);
}
int main()
{//freopen("sample.in","r",stdin);//freopen("sample.out","w",stdout);ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);cin>>n>>m;for(int i=1;i<=n;i++){cin>>s+1;insert(s);}build();init();memset(dp,-0x3f,sizeof(dp));dp[0][0]=0;for(int lv=0;lv<m;lv++){for(int p=0;p<=idx;p++){for(int i=0;i<3;i++){int v=ch[p][i];dp[lv+1][v]=max(dp[lv+1][v],dp[lv][p]+tot[v]);}}}for(int i=0;i<=idx;i++)ans=max(ans,dp[m][i]);cout<<ans;return 0;
}