1. 程式人生 > >P3041 [USACO12JAN]視頻遊戲的連擊Video Game Combos

P3041 [USACO12JAN]視頻遊戲的連擊Video Game Combos

++ index pan tin code 一個 color 分析 space

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 }

P3041 [USACO12JAN]視頻遊戲的連擊Video Game Combos