BZOJ2580:[USACO]Video Game(AC自动机,DP)

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?
给出n个ABC串combo[1..n]和k,现要求生成一个长k的字符串S,问S与word[1..n]的最大匹配数

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

用$End[i]$表示$i$结点及其所有的后缀(也就是其$fail$树上所有祖先)的字符串个数。

设$f[i][j]$表示匹配到$i$点,长度为$j$,转移比较显然。

Code

 1 #include<iostream>
 2 #include<cstring>
 3 #include<cstdio>
 4 #include<queue>
 5 #define N (1009)
 6 using namespace std;
 7 
 8 int n,k,cnt,ans,f[N][N];
 9 int Son[N][3],End[N],Fail[N];
10 char s[N];
11 queue<int>q;
12 
13 void Insert(char s[])
14 {
15     int now=0,len=strlen(s);
16     for (int i=0; i<len; ++i)
17     {
18         int x=s[i]-'A';
19         if (!Son[now][x]) Son[now][x]=++cnt;
20         now=Son[now][x];
21     }
22     ++End[now];
23 }
24 
25 void Build_Fail()
26 {
27     for (int i=0; i<3; ++i)
28         if (Son[0][i]) q.push(Son[0][i]);
29     while (!q.empty())
30     {
31         int now=q.front(); q.pop();
32         End[now]+=End[Fail[now]];
33         for (int i=0; i<3; ++i)
34         {
35             if (!Son[now][i])
36             {
37                 Son[now][i]=Son[Fail[now]][i];
38                 continue;
39             }
40             Fail[Son[now][i]]=Son[Fail[now]][i];
41             q.push(Son[now][i]);
42         }
43     }
44 }
45 
46 int main()
47 {
48     scanf("%d%d",&n,&k);
49     for (int i=1; i<=n; ++i)
50         scanf("%s",s), Insert(s);
51     Build_Fail();
52     memset(f,-0x7f,sizeof(f));
53     f[0][0]=0;
54     for (int i=0; i<=k; ++i)
55         for (int j=0; j<=cnt; ++j)
56             for (int k=0; k<3; ++k)
57                 f[Son[j][k]][i+1]=max(f[Son[j][k]][i+1],f[j][i]+End[Son[j][k]]);
58     for (int i=1; i<=cnt; ++i) ans=max(ans,f[i][k]);
59     printf("%d\n",ans);
60 }
posted @ 2019-02-25 14:29  Refun  阅读(212)  评论(0编辑  收藏  举报