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 }