传送门
SPOJ10502
Luogu3041
Description
Bessie is playing a video game! In the game, the three letters ‘A’, ‘B’,and ‘C’ are the only valid buttons. Bessie may press the buttons in any order she likes; however, there are only N distinct combos possible (1 <= N<= 20). Combo i is represented as a string S_i which has a length between 1 and 15 and contains only the letters ‘A’, ‘B’, and ‘C’.
Whenever Bessie presses a combination of letters that matches with a combo, she gets one point for the combo. Combos may overlap with each other or even finish at the same time! For example if N = 3 and the three possible combos are “ABA”, “CB”, and “ABACB”, and Bessie presses “ABACB”, she will end with 3 points. Bessie may score points for a single combo more than once.
Bessie of course wants to earn points as quickly as possible. If she presses exactly K buttons (1 <= K <= 1,000), what is the maximum number of points she can earn?
给你个模式串(每个长度≤15,1≤N≤20),串中只含有“ABC”三种字母。求一长度为K(1≤K≤1000)的字符串,使得匹配数最大(重复匹配计多次),输出最大值。
Input
- Line 1: Two space-separated integers: N and K.
- Lines 2..N+1: Line i+1 contains only the string S_i, representing combo i.
Output
- Line 1: A single integer, the maximum number of points Bessie can obtain.
Sample Input
3 7
ABA
CB
ABACB
Sample Output
4
Hint
The optimal sequence of buttons in this case is ABACBCB, which gives 4 points–1 from ABA, 1 from ABACB, and 2 from CB.
Solution
- AC自动机模板+DP
- val[u]表示后缀树上u及其子孙中危险节点总和。(此处后缀树指fail指针反向构成的树)
- f[step][u]表示第step步走到u节点的最优答案
- 需要注意的是如果当前危险节点的模式串长度小于step,答案是不可以更新的,p数组用来判断这个,相当于表示该状态有没有到达过。
第一次由于这个WA掉了
Code
#include <iostream>
#include <cstdio>
#include <cmath>
#include <queue>
#include <cstring>
#include <algorithm>
using namespace std;
queue <int>q;
char s[27];
int n,m,sz;
int f[1007][307],ch[307][7],val[307],fail[307];
bool p[1007][307];
void insert(char *s,int id){
int u=1,n=strlen(s);
for (int i=0;i<n;i++){
int c=s[i]-'A';
if (!ch[u][c]){
//memset(ch[sz],0,sizeof(ch[sz]));
//val[sz]=0;
ch[u][c]=++sz;
}
u=ch[u][c];
}
val[u]=1;
}
void getFail(){
int rt=1;
fail[rt]=1;
for (int i=0;i<3;i++){
int u=ch[rt][i];
fail[u]=rt;
if (u){fail[u]=rt; q.push(u);}
else ch[rt][i]=rt;
}
while (!q.empty()){
int u=q.front(); q.pop();
for (int i=0;i<3;i++){
int v=ch[u][i];
if (v){fail[v]=ch[fail[u]][i]; q.push(v);}
else ch[u][i]=ch[fail[u]][i];
}
if (val[fail[u]]) val[u]+=val[fail[u]];
}
}
int main(){
scanf("%d%d",&n,&m);
sz=1;
for (int i=1;i<=n;i++){
scanf("%s",s);
insert(s,i);
}
getFail();
//printf("sz=%d\n",sz);
p[0][1]=1;
for (int step=0;step<m;step++)
for (int u=1;u<=sz;u++)
if (p[step][u])
for (int v=0;v<3;v++){
int i=ch[u][v];
p[step+1][i]=p[step][u];
f[step+1][i]=max(f[step+1][i],f[step][u]+val[i]);
}
//for (int i=1;i<=sz;i++) printf("%d ",val[i]); printf("\n");
int ans=0;
/*
for (int i=0;i<=7;i++)
for (int j=1;j<=sz;j++)
printf("f[%d][%d]=%d\n",i,j,f[i][j]);
*/
for (int i=1;i<=sz;i++) ans=max(ans,f[m][i]);
printf("%d",ans);
return 0;
}
//SP10502
//Luogu 3041