http://acm.hdu.edu.cn/showproblem.php?pid=4057
题意:给出n个子串,串只包含‘A’,'C','G','T'四种字符,你现在需要构造出一个长度为l的串,如果这个串里面包含了某个子串,那么答案就会+val[i](如果这个串被使用过了,就不会再有贡献了),要使得构造出来的串的答案最大,问是多少。
思路:只能想到是AC自动机的题目,然后乱搞出一个错误的方法,没想到是这样的操作。
n只有10,因此才1024,开一个dp[l][sz][st]的数组,l代表当前的字符串长度,sz代表当前遍历的结点,st代表当前的状态(二进制表示使用了哪些字符串),这里的长度用滚动数组优化。
方程:dp[now][nxt[j][x]][k|val[nxt[j][x]]] = dp[pre][j][k]; (当且仅当dp[pre][j][k]状态可取)
nxt[j][x]代表j结点的下一个状态,val[now]代表now这个结点是哪个字符串的终点,因此k|val[nxt[j][x]]就是当前拥有的字符串的状态+下一个结点拥有的字符串的状态。
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <queue> 5 using namespace std; 6 #define N 1010 7 #define INF 0x3f3f3f3f 8 int nxt[N][4], fail[N], val[N], rt, sz, n, l, num[11]; 9 bool dp[2][N][(1<<10)+10]; 10 char s[105]; 11 int newnode() { 12 for(int i = 0; i < 4; i++) nxt[sz][i] = -1; 13 val[sz++] = 0; 14 return sz - 1; 15 } 16 void init() { 17 sz = 0; rt = newnode(); 18 } 19 int Turn(char c) { 20 if(c == 'A') return 0; 21 if(c == 'C') return 1; 22 if(c == 'G') return 2; 23 return 3; 24 } 25 void Insert(int id) { 26 int len = strlen(s); 27 int now = rt; 28 for(int i = 0; i < len; i++) { 29 int c = Turn(s[i]); 30 if(nxt[now][c] == -1) nxt[now][c] = newnode(); 31 now = nxt[now][c]; 32 } 33 val[now] |= (1 << id); 34 } 35 void Build() { 36 queue<int> que; 37 while(!que.empty()) que.pop(); 38 fail[rt] = rt; 39 for(int i = 0; i < 4; i++) { 40 if(nxt[rt][i] == -1) nxt[rt][i] = rt; 41 else fail[nxt[rt][i]] = rt, que.push(nxt[rt][i]); 42 } 43 while(!que.empty()) { 44 int now = que.front(); que.pop(); 45 val[now] |= val[fail[now]]; // 如果fail指向的结点是有状态的,应该加上!!! 46 for(int i = 0; i < 4; i++) { 47 if(nxt[now][i] == -1) nxt[now][i] = nxt[fail[now]][i]; 48 else fail[nxt[now][i]] = nxt[fail[now]][i], que.push(nxt[now][i]); 49 } 50 } 51 } 52 void Solve() { 53 int pre = 0, now = 1; 54 memset(dp, 0, sizeof(dp)); 55 dp[pre][0][0] = 1; 56 for(int i = 0; i < l; i++) { 57 memset(dp[now], 0, sizeof(dp[now])); 58 for(int j = 0; j < sz; j++) { 59 for(int k = 0; k < (1 << n); k++) { 60 if(!dp[pre][j][k]) continue; 61 for(int x = 0; x < 4; x++) { 62 dp[now][nxt[j][x]][k|val[nxt[j][x]]] = dp[pre][j][k]; // 哪些状态可以取 63 // nxt[j][x] 下一个结点 64 // k | val[nxt[j][x]] 当前状态加上下一个结点有的状态 65 } 66 } 67 } 68 swap(now, pre); 69 } 70 int ans = -INF, res; now = l % 2; 71 for(int i = 0; i < sz; i++) { 72 for(int j = 0; j < (1 << n); j++) { 73 if(!dp[now][i][j]) continue; 74 res = 0; 75 for(int k = 0; k < n; k++) 76 if(j & (1 << k)) res += num[k]; 77 ans = ans > res ? ans : res; 78 } 79 } 80 if(ans >= 0) printf("%d ", ans); 81 else puts("No Rabbit after 2012!"); 82 } 83 84 int main() { 85 while(~scanf("%d%d", &n, &l)) { 86 init(); 87 for(int i = 0; i < n; i++) scanf("%s %d", s, &num[i]), Insert(i); 88 Build(); 89 Solve(); 90 } 91 return 0; 92 } 93 94 /* 95 3 2 96 A -1 97 G -1 98 C -1 99 */