HDU 4057 Rescue the Rabbit (AC自动机+DP)

http://acm.hdu.edu.cn/showproblem.php?pid=4057

Rescue the Rabbit
Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1482    Accepted Submission(s): 430

Problem Description

Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, and Dr. X wants to take some rabbits to Noah‘s Ark, or there are no rabbits any more.

A rabbit‘s genes can be expressed as a string whose length is l (1 ≤ l ≤ 100) containing only ‘A‘, ‘G‘, ‘T‘, ‘C‘. There is no doubt that Dr. X had a in-depth research on the rabbits‘ genes. He found that if a rabbit gene contained a particular gene segment,
we could consider it as a good rabbit, or sometimes a bad rabbit. And we use a value W to measure this index.

We can make a example, if a rabbit has gene segment "ATG", its W would plus 4; and if has gene segment "TGC", its W plus -3. So if a rabbit‘s gene string is "ATGC", its W is 1 due to ATGC contains both "ATG"(+4) and "TGC"(-3). And if another rabbit‘s gene string
is "ATGATG", its W is 4 due to one gene segment can be calculate only once.

Because there are enough rabbits on Earth before 2012, so we can assume we can get any genes with different structure. Now Dr. X want to find a rabbit whose gene has highest W value. There are so many different genes with length l, and Dr. X is not good at
programming, can you help him to figure out the W value of the best rabbit.

Input

There are multiple test cases. For each case the first line is two integers n (1 ≤ n ≤ 10),l (1 ≤ l ≤ 100), indicating the number of the particular gene segment and the length of rabbits‘ genes.

The next n lines each line contains a string DNAi and an integer wi (|wi| ≤ 100), indicating this gene segment and the value it can contribute to a rabbit‘s W.

Output

For each test case, output an integer indicating the W value of the best rabbit. If we found this value is negative, you should output "No Rabbit after 2012!".

Sample Input

2 4
ATG 4
TGC -3

1 6
TGC 4

4 1
A -1
T -2
G -3
C -4

Sample Output

4
4
No Rabbit after 2012!

Hint

case 1:we can find a rabbit whose gene string is ATGG(4), or ATGA(4) etc.
case 2:we can find a rabbit whose gene string is TGCTGC(4), or TGCCCC(4) etc.
case 3:any gene string whose length is 1 has a negative W.

Author

HONG, Qize

Source

2011 Asia Dalian Regional Contest

题意:

有ATCG4个字母,要求构成一个长度为l的字符串,给出n个模式串及其权值,问能构成的字符串中最大的权值和是多少,每个模式串只计算一次。

分析:

很容易想到是AC自动机。我们在AC自动机上找到长度为l的可行方案,并求出最大值即可。用dp[i][j][k]表示字符串长度为i时,AC自动机上第j个结点是否可达状态k。因为模式串只有10种,所以最多有2^10个状态,状压一下就行了,然后就是长度为i的字符串只由第i-1个变过来,所以可以用滚动数组。

/*
 *
 * Author : fcbruce <[email protected]>
 *
 * Time : Thu 13 Nov 2014 08:23:41 PM CST
 *
 */
#include <cstdio>
#include <iostream>
#include <sstream>
#include <cstdlib>
#include <algorithm>
#include <ctime>
#include <cctype>
#include <cmath>
#include <string>
#include <cstring>
#include <stack>
#include <queue>
#include <list>
#include <vector>
#include <map>
#include <set>
#define sqr(x) ((x)*(x))
#define LL long long
#define itn int
#define INF 0x3f3f3f3f
#define PI 3.1415926535897932384626
#define eps 1e-10

#ifdef _WIN32
  #define lld "%I64d"
#else
  #define lld "%lld"
#endif

#define maxm
#define maxn 1007

using namespace std;

char gene[17][233];
int w[17];
int dp[2][maxn][2333];

int q[maxn<<1];

const int maxsize = 4;
struct ACauto
{
  int ch[maxn][maxsize];
  int val[maxn],last[maxn],nex[maxn];
  int sz;

  ACauto()
  {
    sz=1;
    val[0]=0;
    memset(ch[0],0,sizeof ch[0]);
  }

  void clear()
  {
    sz=1;
    val[0]=0;
    memset(ch[0],0,sizeof ch[0]);
  }

  int idx(char c)
  {
    switch (c)
    {
      case 'A': return 0;
      case 'T': return 1;
      case 'C': return 2;
      case 'G': return 3;
    }
  }

  void insert(const char *s,int v)
  {
    int u=0;
    for (int i=0;s[i]!='\0';i++)
    {
      int c=idx(s[i]);
      if (ch[u][c]==0)
      {
        memset(ch[sz],0,sizeof ch[sz]);
        val[sz]=0;
        ch[u][c]=sz++;
      }
      u=ch[u][c];
    }
    val[u]=v;
  }

  void get_fail()
  {
    int f=0,r=-1;
    nex[0]=0;
    for (itn c=0;c<maxsize;c++)
    {
      int u=ch[0][c];
      if (u!=0)
      {
        nex[u]=0;
        q[++r]=u;
      }
    }

    while (f<=r)
    {
      int x=q[f++];
      for (int c=0;c<maxsize;c++)
      {
        int u=ch[x][c];
        if (u==0)
        {
          ch[x][c]=ch[nex[x]][c];
          continue;
        }
        q[++r]=u;
        int v=nex[x];
        nex[u]=ch[v][c];
        val[u]|=val[nex[u]];
      }
    }
  }

  int calc(int x,int n)
  {
    int score=0;
    for (int i=0;i<n;i++)
      if (x&(1<<i)) score+=w[i];
    return score;
  }

  int go(int l,int n)
  {
    memset(dp,0,sizeof dp);
    dp[0][0][0]=true;

    int x=1;
    for (int i=1;i<=l;i++,x^=1)
    {
      memset(dp[x],0,sizeof dp[x]);
      for (int j=0;j<sz;j++)
        for (int k=0;k<4;k++)
          for (int l=0;l<(1<<n);l++)
            if (dp[x^1][j][l]) dp[x][ch[j][k]][l|val[ch[j][k]]]=true;
    }

    int MAX=-1;
    for (int i=0;i<(1<<n);i++)
    {
      int cur=calc(i,n);
      if (cur<=MAX) continue;
      for (int j=0;j<=sz;j++)
        if (dp[x^1][j][i])
        {
          MAX=cur;
          break;
        }
    }

    return MAX;
  }
}acauto;

int main()
{
#ifdef FCBRUCE
  freopen("/home/fcbruce/code/t","r",stdin);
#endif // FCBRUCE

  int n,l;

  while (scanf("%d%d",&n,&l)==2)
  {
    acauto.clear();

    for (int i=0;i<n;i++)
    {
      scanf("%s %d",gene[i],w+i);
      acauto.insert(gene[i],1<<i);
    }

    acauto.get_fail();

    int MAX=acauto.go(l,n);

    if (MAX>=0) printf("%d\n",MAX);
    else puts("No Rabbit after 2012!");
  }

  return 0;
}
时间: 2024-10-29 19:11:44

HDU 4057 Rescue the Rabbit (AC自动机+DP)的相关文章

hdu 4057 Rescue the Rabbit(AC自动机+状压dp)

题目链接:hdu 4057 Rescue the Rabbit 题意: 给出一些模式串,每个串有一定的价值,现在构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次. 题解: 由于每个模式串最多统计一次,所以我们要考虑记录是否已经存在该串. 考虑dp[i][j][k]表示当前考虑到i的长度,存在的串的组合为j,在AC自动机上走到了k这个节点的状态. 然后转移一下就能将所有能到达的状态走到.然后取一个最大值就行了. 1 #include<bits/stdc++.h> 2 #defin

Zoj 3545 Rescue the Rabbit(ac自动机+dp)

题目大意: 给出的DNA序列有一个权值,请构造一个长度为I的DNA序列使得在这段DNA序列的权值最大.如果为负数就输出噼里啪啦... 思路分析: 构造序列就是在ac自动机上走,求最大要用到dp dp[i][j][k] 表示现在构造到了长度 i .此时的我们把当前字符放在j节点,并且满足了k状态.k是一个10位的2进制状态压缩. 注意这道题上有坑就是一个序列可能有多个权值.所以不能直接赋值,需要用位或. #include <cstdio> #include <iostream> #i

HDU 3341 Lost&#39;s revenge AC自动机+dp

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3757    Accepted Submission(s): 1020 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

Hdu 3341 Lost&#39;s revenge (ac自动机+dp+hash)

题目大意: 给出很多个DNA串,每一个串的价值为1,最后给出一个长串,要你重新排列最后的串使之它所有的子串的权值和最大. 思路分析: 最先容易想到的思路就是搜!管她3721..直接一个字符一个字符的码,然后在AC自动机上判断最后的权值.TLE哟. 然后发现搜过不去,那就dp咯.再容易想到的就是dp[i][a][b][c][d] 表示此时遍历AC自动机的节点在i,然后构成了a个A,b个G,c个C,d个T的权值. 再一看内存,500*40*40*40*40...然后...就没有然后了 再想,因为它说

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理)

hdu 4878 ZCC loves words(AC自动机+dp+矩阵快速幂+中国剩余定理) 题意:给出若干个模式串,总长度不超过40,对于某一个字符串,它有一个价值,对于这个价值的计算方法是这样的,设初始价值为V=1,假如这个串能匹配第k个模式串,则V=V*prime[k]*(i+len[k]),其中prime[k]表示第k个素数,i表示匹配的结束位置,len[k]表示第k个模式串的长度(注意,一个字符串可以多次匹配同意个模式串).问字符集为'A'-'Z'的字符,组成的所有的长为L的字符串,

HDU 2457 DNA repair (AC自动机 + DP)

题目链接:DNA repair 解析:给出n个致病DNA序列,给一段DNA片段,问最少修改多少个碱基才能修复这段DNA序列中的所有致病序列. AC自动机 + DP. 将n个致病DNA序列构成一个自动机. 令DP[i][j]表示长度为i走到节点j是所需改变的最少个数. 状态转移时,枚举下一步所有可能的碱基,然后判断该碱基是否达到匹配状态,若能,则安全转移,继续枚举下一个碱基:否则在不匹配的前提下,看该碱基加入之后是否跟上一状态相同,若不同,则需修复,即计数加一.若相同,直接转移即可.然后选择其中最

HDU - 6086 Rikka with String AC自动机 + dp

HDU - 6086 前缀和后缀分别建AC自动机, 考虑从两端往中间dp dp[ o ][ i ][ j ][ mask ] 表示放了前面和后面o个, 第一个自动机在 i 位置, 第二个自动机在 j 位置, 拥有的目标串的状态是mask的方案数. 对于跨过两端的东西, 我们最后处理就好了. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #def

HDU - 4758 Walk Through Squares (AC自动机+DP)

Description On the beaming day of 60th anniversary of NJUST, as a military college which was Second Artillery Academy of Harbin Military Engineering Institute before, queue phalanx is a special landscape. Here is a M*N rectangle, and this one can be

hdu4057Rescue the Rabbit(ac自动机+dp)

链接 当时是因为没有做出来这道题才开了自动机的专题,现在看看还是比较简单的. 因为每个病毒串只算一次,只有10个病毒串,可以状压一下哪些状态是可以达到的,最后取一个最大值. 1 #include <iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<stdlib.h> 6 #include<vector> 7 #includ