【题意】:给出n(n<11)个基因串,每个基因串有对应的权值,构造一个长度为l的基因,问最大的权值为多少?重复的基因只能算一次。

【题解】:考虑到最多只有10个基因串,我们可以使用状态压缩。对于串之间的关系,我们可以建立对应的ac自动机,然后在ac自动机上进行状态压缩dp即可。
              dp[i][j][k] i表示长度,j表示基因结尾状态,k表示所含基因的状态
              转移方程,设son为j的孩子节点:
              if(dp[i][j][k]) dp[i+1][son][k|T[son].id] = true;
              实现的时候我用了滚动数组压缩空间,具体操作请看代码。

【代码】:
  1 #include "iostream"
  2 #include "cstdio"
  3 #include "cstring"
  4 using namespace std;
  5 const int kind = 4;
  6 const int maxn = 250;
  7 int score[15];
  8 int root, tot;
  9 char ch[25];
 10 int n, m, l;
 11 int que[maxn], head, tail;
 12 
 13 struct Node {
 14     int child[kind];
 15     int fail;
 16     int id;
 17     void init() {
 18         memset(child, 0sizeof (child));
 19         fail = -1, id = 0;
 20     }
 21 } T[maxn];
 22 
 23 void init() {
 24     root = tot = 0;
 25     T[root].init();
 26 }
 27 
 28 int hash(char ch) {
 29     if(ch == 'A'return 0;
 30     else if(ch == 'C'return 1;
 31     else if(ch == 'G'return 2;
 32     else return 3;
 33 }
 34 
 35 void insert(char *s, int id) {//插入单词
 36     int p = root, index;
 37     while (*s) {
 38         index = hash(*s);
 39         if (!T[p].child[index]) {
 40             T[++tot].init();
 41             T[p].child[index] = tot;
 42         }
 43         p = T[p].child[index];
 44         s++;
 45     }
 46     T[p].id |= 1 << id;
 47 }
 48 
 49 void build_ac_auto() {
 50     head = tail = 0;
 51     que[tail++= root;
 52     while (head < tail) {
 53         int u = que[head++];
 54         for (int i = 0; i < kind; i++) {
 55             if (T[u].child[i]) {
 56                 int son = T[u].child[i];
 57                 int p = T[u].fail;
 58                 if (u == root) T[son].fail = root;
 59                 else {
 60                     T[son].fail = T[p].child[i];
 61                     T[son].id |= T[T[son].fail].id;
 62                 }
 63                 que[tail++= son;
 64             } else {//trie图,设定虚拟节点
 65                 int p = T[u].fail;
 66                 if (u == root) T[u].child[i] = root;
 67                 else T[u].child[i] = T[p].child[i];
 68             }
 69         }
 70     }
 71 }
 72 bool dp[2][205][1<<10];//滚动数组,不用滚动也可以
 73 void solve() {
 74     int mask = 1 << n, now, next;
 75     memset(dp, falsesizeof(dp));
 76     dp[0][0][0= true;
 77     for(int i = 0; i < l; i++) {
 78         now = i % 2;
 79         next = (i + 1% 2;
 80         memset(dp[next], falsesizeof(dp[next]));
 81         for(int j = 0; j <= tot; j++) {
 82             for(int k = 0; k < mask; k++) {
 83                 if(dp[now][j][k]) {
 84                     for(int p = 0; p < kind; p++) {
 85                         int son = T[j].child[p];
 86                         dp[next][son][k|T[son].id] = true;
 87                     }
 88                 }
 89             }
 90         }
 91     }
 92     int ans = -(1 << 30);
 93     now = l % 2;
 94     for(int i = 0; i <= tot; i++) {
 95         for(int j = 0; j < mask; j++) {
 96             if(dp[now][i][j]) {
 97                 int t = 0;
 98                 for(int k = 0; k < n; k++) {
 99                     if(j & (1<< k)) t += score[k];
100                 }
101                 ans = max(ans, t);
102             }
103         }
104     }
105     if(ans < 0) printf("No Rabbit after 2012!\n");
106     else printf("%d\n", ans);
107 }
108 
109 int main() {
110     while(~scanf("%d%d"&n, &l)) {
111         init();
112         for(int i = 0; i < n; i++) {
113             scanf("%s%d", ch, &score[i]);
114             insert(ch, i);
115         }
116         build_ac_auto();
117         solve();
118     }
119     return 0;
120 }