分析

未知定长串中不同已知模板串的出现次数问题,一般做法是AC自动机上dp。

考虑背包,\(dp(i,j,k)\)表示当前串长为\(i\),在AC自动机上对应节点\(j\),已匹配的模板串的状态为\(k\)的情况是否出现。用刷表法向后转移。先枚举不定串长度,再枚举AC自动机上节点,然后枚举已知状态,最后枚举字母边转移。

时间复杂度\(O(l \cdot MaxNode \cdot 2^n \cdot SigmaSize)\)。第一维可以滚动,空间复杂度\(O(MaxNode \cdot 2^n)\)

代码

#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<ctime>
#include<iostream>
#include<string>
#include<vector>
#include<list>
#include<deque>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<complex>
#pragma GCC optimize ("O0")
using namespace std;
template<class T> inline T read(T&x){
    T data=0;
    int w=1;
    char ch=getchar();
    while(!isdigit(ch))
    {
        if(ch=='-')
            w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=10*data+ch-'0',ch=getchar();
    return x=data*w;
}
typedef long long ll;
const int INF=0x7fffffff;

const int MAXN=1010;
const int SigmaSize=4;

bool dp[2][MAXN][1100];
int mp[15];

struct Trie
{
    int next[MAXN][SigmaSize];
    int fail[MAXN];
    int end[MAXN];
    int root,ncnt;
    int newnode()
    {
        for(int i=0;i<SigmaSize;++i)
            next[ncnt][i]=-1;
        end[ncnt++]=0;
        return ncnt-1;
    }
    void init()
    {
        ncnt=0;
        root=newnode();
    }
    int id(char c)
    {
        if(c=='A')
            return 0;
        else if(c=='G')
            return 1;
        else if(c=='T')
            return 2;
        else
            return 3;
    }
    void insert(char*str,int v)
    {
        int now=root;
        int len=strlen(str);
        for(int i=0;i<len;++i)
        {
            int c=id(str[i]);
            if(next[now][c]==-1)
                next[now][c]=newnode();
            now=next[now][c];
        }
        end[now]|=(1<<v);
    }
    void getfail()
    {
        queue<int>Q;
        fail[root]=root;
        for(int i=0;i<SigmaSize;++i)
        {
            if(next[root][i]==-1)
                next[root][i]=root;
            else
            {
                fail[next[root][i]]=root;
                Q.push(next[root][i]);
            }
        }
        while(!Q.empty())
        {
            int now=Q.front();
            Q.pop();
            end[now]|=end[fail[now]];
            for(int i=0;i<SigmaSize;++i)
            {
                if(next[now][i]==-1)
                    next[now][i]=next[fail[now]][i];
                else
                {
                    fail[next[now][i]]=next[fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    void solve(int n,int l)
    {
        memset(dp,0,sizeof(dp));
        dp[0][0][0]=1; // dp[len][node][state]
        int cur=1;
        for(int i=1;i<=l;++i)
        {
            memset(dp[cur],0,sizeof(cur));
            for(int j=0;j<ncnt;++j)
            {
                for(int k=0;k<(1<<n);++k)
                {
                    for(int q=0;q<SigmaSize;++q)
                    {
                        int nxt=next[j][q];
                        dp[cur][nxt][k|end[nxt]]=(dp[cur][nxt][k|end[nxt]]||dp[cur^1][j][k]);
                    }
                }
            }
            cur^=1;
        }
        int ans=-INF;
        for(int i=0;i<ncnt;++i)
            for(int j=0;j<(1<<n);++j)
            {
                if(dp[cur^1][i][j])
                {
                    int sum=0;
                    for(int k=0;k<n;++k)
                        if(j&(1<<k))
                            sum+=mp[k];
                    ans=max(ans,sum);
                }
            }
        if(ans<0)
            printf("No Rabbit after 2012!\n");
        else
            printf("%d\n",ans);
    }
}AC;

char s[110];

int main()
{
//  freopen(".in","r",stdin);
//  freopen(".out","w",stdout);
    int n,l,w;
    while(~scanf("%d %d",&n,&l))
    {
        AC.init();
        for(int i=0;i<n;++i)
        {
            scanf("%s %d",s,&w);
            AC.insert(s,i);
            mp[i]=w;
        }
        AC.getfail();
        AC.solve(n,l);
    }
//  fclose(stdin);
//  fclose(stdout);
    return 0;
}

ZOJ3545 Rescue the Rabbit的更多相关文章

  1. JSOI2009 密码 和 JSOI2007 文本生成器 和 ZOJ3545 Rescue the Rabbit

    密码 众所周知,密码在信息领域起到了不可估量的作用.对于普通的登陆口令,唯一的破解 方法就是暴力破解一逐个尝试所有可能的字母组合,但这是一项很耗时又容易被发现的工 作.所以,为了获取对方的登陆口令,在 ...

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

    Rescue the Rabbit Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

  3. hdu4057 Rescue the Rabbit

    地址:http://acm.hdu.edu.cn/showproblem.php?pid=4057 题目: Rescue the Rabbit Time Limit: 20000/10000 MS ( ...

  4. hdu4057 Rescue the Rabbit(AC自己主动机+DP)

    Rescue the Rabbit Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...

  5. HDU4057 Rescue the Rabbit(AC自动机+状压DP)

    题目大概是给几个DNA片段以及它们各自的权值,如果一个DNA包含某个片段那么它的价值就加上这个片段的权值,同时包含多个相同DNA片段也只加一次,问长度l的DNA可能的最大价值. 与HDU2825大同小 ...

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

    题目链接 一个数组开小了一点点,一直提示wa,郁闷,这题比上个题简单一点. #include <iostream> #include <cstring> #include &l ...

  7. ZOJ 3545 Rescue the Rabbit(AC自动机+状压DP)(The 2011 ACM-ICPC Asia Dalian Regional Contest)

    Dr. X is a biologist, who likes rabbits very much and can do everything for them. 2012 is coming, an ...

  8. 【HDOJ】4057 Rescue the Rabbit

    挺有意思的一道题目,解法是AC自动机+DP.AC自动机建立fail指针时,一定要注意结点的属性也需要传递.AC自动机结合了trie和kmp的优点.需要注意的是,每个模式串仅计算一次,否则这题很难解. ...

  9. Zoj 3545 Rescue the Rabbit(ac自己主动机+dp)

    标题效果: 鉴于DNA有一个正确的顺序值.请构造一个长度I的DNA在这个序列使DNA正确的顺序值极大.它被认为是负的输出噼啪. .. IDEAS: 施工顺序是,ac己主动机上走,求最大要用到dp dp ...

随机推荐

  1. java中的static关键字 学习总结

    使用static关键字修饰的变量和方法为静态变量.静态方法. 非静态方法可以访问静态变量/方法和非静态变量/方法,但静态方法只能访问静态变量/方法. 可以看到在静态方法中调用非静态变量和非静态方法时, ...

  2. English trip -- 国际音标表

    26个字母音标表 A a [ei] B b [bi:] C c [si:] D d [di:] E e [i:] F f [ef] G g [dʒi:] H h [eit∫] I i [ai] J j ...

  3. LeetCode--125--验证回文串

    问题描述: 好 times out: class Solution(object): def isPalindrome(self, s): """ :type s: st ...

  4. 3-20 标准库:find库; 学习编程语言3节课(大多是旧识,全*栈)3-21 面向对象. Percent Strings; 元编程和Rails的相互理解

    Find The Find module supports the top-down traversal of a set of file paths.(一系列文件的路径的遍历) find(*path ...

  5. php--------删除数组的第一个元素和最后一个元素

    对于一个php数组,该如何删除该数组的第一个元素或者最后一个元素呢?其实这两个过程都可以通过php自带的函数 array_pop 和 array_shift 来完成,下面就具体介绍一下如何来操作. ( ...

  6. Anton and School - 2 CodeForces - 785D (组合计数,括号匹配)

    大意: 给定括号字符串, 求多少个子序列是RSGS. RSGS定义如下: It is not empty (that is n ≠ 0). The length of the sequence is ...

  7. JVM笔记(三) 垃圾收集器(2)收集算法

    垃圾收集器2:收集算法 主要通过阅读<深入了解Java虚拟机>(周志明 著)和网络资源汇集而成,为本人学习JVM的笔记.同时,本文理论基于JDK 1.7版本,暂不考虑 1.8和1.9 的新 ...

  8. json添加数据

    <!doctype html> <html> <head> <meta charset="utf-8"> <title> ...

  9. Android JNI作用及其详解

    Android JNI作用及其详解 Java Native Interface (JNI)标准是Java平台的一部分,它允许Java代码和其他语言写的代码进行交互.JNI 是本地编程接口,它使得在 J ...

  10. maven多环境配置

    我们在开发项目的时候,往往会有好几个环境.比如开发.预发布(测试).产品,每个环境一般用到配置都不一样,最典型的就是数据库,开发的数据库与产品的数据库肯定是不一样的,如果要多个环境的切换就得改配置,这 ...