分析

未知定长串中不同已知模板串的出现次数问题,一般做法是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. English trip -- VC(情景课)5 Around Town

     Around Town  城市周围 Talk about the picture 看图说话 sentences Where are you? I'm in the Meten classroom. ...

  2. JVM中对象的内存布局与访问定位

      一.对象的内存布局 已主流的HotSpot虚拟机来说,   在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域:对象头(Header).实例数据(Instance Data)和对齐填 ...

  3. php--------使用 isset()判断字符串长度速度比strlen()更快

    isset()速度为什么比strlen()更快呢? strlen()函数函数执行起来相当快,因为它不做任何计算,只返回在zval 结构(C的内置数据结构,用于存储PHP变量)中存储的已知字符串长度.但 ...

  4. FastDFS install

    Version: os: centos7 x64 FastDFS: 5.05 libfastcommon: latest 1. dwonload libfastcommon https://githu ...

  5. python-day41--约束条件

    一 .介绍 约束条件与数据类型的宽度一样,都是可选参数 作用:用于保证数据的完整性和一致性主要分为: PRIMARY KEY (PK) 标识该字段为该表的主键,可以唯一的标识记录 FOREIGN KE ...

  6. Xshell如何设置,当连接断开时保留Session,保留原文字

    Xshell [1]  是一个强大的安全终端模拟软件,它支持SSH1, SSH2, 以及Microsoft Windows 平台的TELNET 协议.Xshell 通过互联网到远程主机的安全连接以及它 ...

  7. BZOJ 1601 [Usaco2008 Oct]灌水 (最小生成树)

    题意 Farmer John已经决定把水灌到他的n(1<=n<=300)块农田,农田被数字1到n标记.把一块土地进行灌水有两种方法,从其他农田饮水,或者这块土地建造水库. 建造一个水库需要 ...

  8. ubuntu下没有Language Support

    sudo apt-get installlanguage-selector-gnome

  9. 【VUE】@click加上v-bind绑定切换类名及动画事件

    好长的名字... 效果是 点击元素,通过改变类名的方式让其改变颜色+移动动画效果,这里用的是v-bind和@click 废话不说 show me the code! <div id=" ...

  10. vue中上传文件相同文件名没反应

    vue项目中会遇到上传文件的需求,jquery会有一些插件很方便,如果不使用插件网上的方法没有太容易的而且很多是原生JS或者基于jQuery操作dom结构的.那么在vue项目中如何实现呢,还有如何模拟 ...