P3041 [USACO12JAN]视频游戏的连击Video Game Combos
https://www.luogu.org/problemnew/show/P3041
分析:
AC自动机。
建立AC自动机,然后dp[i][j]表示经过了i个字符,到达自动机上j这个位置,的得分。
那么dp[i-1][j] + val[ch[j][k]] -> dp[i][ch[j][k]]。
表示从j点,往前走一步,加上新加一个字符产生的贡献。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 const int N = 550; 6 int ch[N][3], fail[N], last[N], val[N], f[1010][N], q[N], L, R, Index = 1; 7 char s[22]; 8 9 void Insert(char *s) { 10 int u = 0, len = strlen(s); 11 for (int i=0; i<len; ++i) { 12 int c = s[i] - ‘A‘; 13 if (!ch[u][c]) ch[u][c] = ++Index; 14 u = ch[u][c]; 15 } 16 val[u] ++; 17 } 18 void build() { 19 L = 1, R = 0; fail[0] = 0; 20 for (int c=0; c<3; ++c) { 21 int u = ch[0][c]; 22 if (u) q[++R] = u, fail[u] = last[u] = 0; 23 } 24 while (L <= R) { 25 int u = q[L++]; 26 for (int c=0; c<3; ++c) { 27 int v = ch[u][c]; 28 if (!ch[u][c]) { 29 ch[u][c] = ch[fail[u]][c]; 30 continue; 31 } 32 q[++R] = v; 33 int p = fail[u]; 34 while (p && !ch[p][c]) p = fail[p]; 35 fail[v] = ch[p][c]; 36 } 37 val[u] += val[fail[u]]; 38 } 39 } 40 41 int main () { 42 43 int n,m; cin >> n >> m; 44 for (int i=1; i<=n; ++i) { 45 scanf("%s",s); 46 Insert(s); 47 } 48 build(); 49 memset(f, -0x3f, sizeof(f)); 50 f[0][0] = 0; 51 52 // f[i][j]表示用了i个字符,在自动机的j号位置,可以得多少分 53 for (int i=1; i<=m; ++i) 54 for (int j=0; j<=Index; ++j) 55 for (int k=0; k<3; ++k) 56 f[i][ch[j][k]] = max(f[i][ch[j][k]], f[i-1][j]+val[ch[j][k]]); 57 // 从j这个位置,经过字符k到达的点的得分为 经过i-1个点到j的得分+经过i个点到ch[j][k]的得分 58 59 int Ans = 0; 60 for (int i=0; i<=Index; ++i) Ans = max(Ans, f[m][i]); 61 cout << Ans; 62 63 return 0; 64 }
原文地址:https://www.cnblogs.com/mjtcn/p/9356599.html
时间: 2024-10-07 10:26:15