给定 \(N\) 个模式串。一个母串的分数定义为能与模式串匹配的次数,可以与同一个模式串多次匹配。问一个长度为 \(K\) 的母串最多能获得多少分。\(N\leq 20,K \leq 1000\)

Solution

考虑在 AC 自动机上 DP,令 \(f[i][j]\) 表示走了 \(i\) 个字符,到达结点 \(j\),则

\[f[i][j]+val[ch[j][k]] \to f[i+1][ch[j][k]] \]

其中 \(val[p]\) 表示结点 \(p\) 到 fail 树根的链上有多少个末端

#include <bits/stdc++.h>
using namespace std;
int val[1005],ch[1005][3],fi[1005],dp[1005][1005],ind,n,m;
char str[1005];
void insert(char *s){
	int len=strlen(s),p=0;
	for(int i=0;i<len;i++){
		int v=s[i]-'A';
		if(!ch[p][v]) ch[p][v]=++ind;
		p=ch[p][v];
	}
	val[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 p=q.front(); q.pop();
		for(int i=0;i<3;i++)
			if(ch[p][i]) fi[ch[p][i]]=ch[fi[p]][i], q.push(ch[p][i]);
			else ch[p][i]=ch[fi[p]][i];
		val[p]+=val[fi[p]];
	}
}
int main(){
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++) scanf("%s",&str), insert(str);
	build();
	memset(dp,0x80,sizeof dp);
	for(int i=0;i<=m;i++) dp[i][0]=0;
	for(int i=1;i<=m;i++){
		for(int j=0;j<=ind;j++){
			for(int k=0;k<3;k++){
				dp[i][ch[j][k]]=max(dp[i][ch[j][k]],dp[i-1][j]+val[ch[j][k]]);
			}
		}
	}
	int ans=0;
	for(int i=0;i<=ind;i++)
		ans=max(ans,dp[m][i]);
	printf("%d\n",ans);
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2021-10-18
  • 2021-11-09
  • 2021-06-27
  • 2021-10-16
  • 2021-05-23
  • 2021-08-19
猜你喜欢
  • 2021-08-13
  • 2022-01-15
  • 2022-12-23
  • 2021-09-22
  • 2021-11-12
  • 2022-12-23
  • 2022-03-11
相关资源
相似解决方案