zoukankan      html  css  js  c++  java
  • Codeforces 86C Genetic engineering (AC自己主动机+dp)

    题目大意:

    要求构造一个串,使得这个串是由所给的串相连接构成,连接能够有重叠的部分。


    思路分析:

    首先用所给的串建立自己主动机,每一个单词节点记录当前节点可以达到的最长后缀。

    開始的时候想的是dp[i][j]表示长度为i,走到自己主动机的j节点的答案。

    可是显然既然是能够反复覆盖的,那么每个节点的dp值都并非最优的。由于能够从一个地方截断去连接另外一个串。

    所以正确姿势就是dp [i] [j] [k] 表示构造到了长度为 i 的串, 如今这个串后面有k 个字符是没有找到有效的节点的,然后在自己主动机上走到了j。

    那么转移的时候,就有两种情况。

    isword >= k+1。

    。。

    为什么是k+1 由于我们如今是去找的儿子节点,已经加1了。这种话就是这个节点能够全然覆盖没有匹配到的k个。换句话说就是让后面的k个字符找到了合法节点去匹配。那么就转移到dp [i+1] [j->next] [0]...

    否则,假设k+1<=10 那么就让后面这个继续失配,那么久直接转移到 dp [i+1][j->next][k+1]...


    最后累加答案。


    #include <cstdio>
    #include <iostream>
    #include <cstring>
    #include <algorithm>
    #include <utility>
    #include <string>
    #include <vector>
    #define inf 0x3f3f3f3f
    using namespace std;
    const int mod = 1000000009;
    const char tab = 'a';
    const int max_next = 4;
    int rev[256];
    struct trie
    {
        struct trie *fail;
        struct trie *next[max_next];
        int isword;
        int index;
    };
    struct AC
    {
        trie *que[100005],*root,ac[100005];
        int head,tail;
        int idx;
        trie *New()
        {
            trie *temp=&ac[idx];
            for(int i=0;i<max_next;i++)temp->next[i]=NULL;
            temp->fail=NULL;
            temp->isword=0;
            temp->index=idx++;
            return temp;
        }
        void init()
        {
            idx=0;
            root=New();
        }
        void Insert(trie *root,char *word,int len){
            trie *t=root;
            for(int i=0;i<len;i++){
                if(t->next[rev[word[i]]]==NULL)
                    t->next[rev[word[i]]]=New();
                t=t->next[rev[word[i]]];
            }
            t->isword=len;
        }
        void acbuild(trie *root){
            int head=0,tail=0;
            que[tail++]=root;
            root->fail=NULL;
            while(head<tail){
                trie *temp=que[head++],*p;
                for(int i=0;i<max_next;i++){
                     if(temp->next[i]){
                        if(temp==root)temp->next[i]->fail=root;
                        else {
                            p=temp->fail;
                            while(p!=NULL){
                                if(p->next[i]){
                                    temp->next[i]->fail=p->next[i];
                                    break;
                                }
                                p=p->fail;
                            }
                            if(p==NULL)temp->next[i]->fail=root;
                        }
                        if(temp->next[i]->fail->isword)
                            temp->next[i]->isword=max(temp->next[i]->isword,temp->next[i]->fail->isword);
                        que[tail++]=temp->next[i];
                     }
                     else if(temp==root)temp->next[i]=root;
                     else temp->next[i]=temp->fail->next[i];
                }
            }
        }
        void tra()
        {
            for(int i=0;i<idx;i++)
            {
                if(ac[i].fail!=NULL)printf("fail = %d ",ac[i].fail->index);
                for(int k=0;k<max_next;k++)
                    printf("%d ",ac[i].next[k]->index);
                puts("");
            }
        }
    }sa,sb;
    string cq[55];
    char word[55];
    int dp[1005][105][11];
    void add(int &a,int b)
    {
        a+=b;
        if(a>=mod)a-=mod;
    }
    int solve(int L)
    {
        memset(dp,0,sizeof dp);
        dp[0][0][0]=1;
        for(int i=0;i<L;i++)
        {
            for(int j=0;j<sa.idx;j++)
            {
                for(int k=0;k<10;k++)
                {
                    for(int d=0;d<4;d++)
                    {
                        if(sa.ac[j].next[d]->isword>=k+1)
                            add(dp[i+1][sa.ac[j].next[d]->index][0],dp[i][j][k]);
                        else if(k+1<=10)
                            add(dp[i+1][sa.ac[j].next[d]->index][k+1],dp[i][j][k]);
                    }
                }
            }
        }
        int ans=0;
        for(int i=0;i<sa.idx;i++)
        {
            add(ans,dp[L][i][0]);
        }
        return ans;
    }
    
    int main()
    {
        rev['A']=0;
        rev['C']=1;
        rev['G']=2;
        rev['T']=3;
        int m,L;
        while(cin>>L>>m)
        {
            sa.init();
            for(int i=1;i<=m;i++)
            {
                cin>>word;
                sa.Insert(sa.root,word,strlen(word));
            }
            sa.acbuild(sa.root);
            printf("%d
    ",solve(L));
        }
        return 0;
    }
    


  • 相关阅读:
    将Excel表中的数据导入到数据库
    别人面试的学习路线
    和同门一起做的PHP网站
    正则表达式
    python 编码形式简单入门
    游戏开发者面临的几大问题
    quick-cocos2d-x与 cocos2d-x的关系
    cocos2dx中的坐标系统
    重载new和delete来检测内存泄漏
    VS下使用Google Protobuf完成SOCKET通信
  • 原文地址:https://www.cnblogs.com/jhcelue/p/6743472.html
Copyright © 2011-2022 走看看