【Luogu】P2536病毒检测(Trie上DP)

  题目链接

  这道题我写了个01DP,f[i][j]表示跑到Trie上第i个节点,匹配到字符串第j位行不行

  然后重点在*号无限匹配怎么处理

  经过一番脑洞我们可以发现*号无限匹配可以拆成两种情况:

  1:匹配数无条件+1,但是字符串仍然匹配到底j位

  2:直接跳过去了qwq

  对应设计状态转移方程就好了

  然后这个算法……我卡时卡空间勉强过

  卡时不知道怎么办……也许能循环展开什么的?

  卡空间的话,可以设滚动数组。

  f[i][j]中的i不再代表Trie上第i个节点,而是代表深度第i层的节点

  DP的时候用dfs的方法DP,DP完了统计一下就可以把原来叶子占用的空间清掉腾给别人

  Orz rqy,这真是个神办法

  

// luogu-judger-enable-o2
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cctype>
#include<queue>
#define maxn 505
#define maxl 1020
using namespace std;
int tree[maxn*maxn][10],tot;
int fail[maxn*maxn];
char s[maxl];
char c[maxl];
int pnt[maxn];
bool f[200000][maxn];

inline int count(char i){
    if(i=='A')    return 0;
    if(i=='T')    return 1;
    if(i=='C')    return 2;
    if(i=='G')    return 3;
    if(i=='*')    return 4;
    return 5;
}

void update(int x){
    int n=strlen(c+1),now=0;
    for(int i=1;i<=n;++i){
        if(tree[now][count(c[i])]==0)    tree[now][count(c[i])]=++tot;
        now=tree[now][count(c[i])];
    }
    pnt[x]=now;
    return;
}

void makefail(){
    queue<int>q;
    for(int i=0;i<6;++i)
        if(tree[0][i])    q.push(tree[0][i]);
    while(!q.empty()){
        int from=q.front();    q.pop();
        for(int i=0;i<6;++i){
            int &now=tree[from][i];
            if(now==0){
                now=tree[fail[from]][i];
                continue;
            }
            fail[now]=tree[fail[from]][i];
            q.push(now);
        }
    }
    return;
}


int main(){
    scanf("%s",s+1);int len=strlen(s+1);
    int n;    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%s",c+1);
        update(i);
    }
    //makefail();
    f[0][0]=1;
    for(int i=0;i<=tot;++i){
        for(register int j=0;j<len;++j){
            if(s[j+1]=='A')    if(tree[i][0])    f[tree[i][0]][j+1]|=f[i][j];
            if(s[j+1]=='T')    if(tree[i][1])    f[tree[i][1]][j+1]|=f[i][j];
            if(s[j+1]=='C')    if(tree[i][2])    f[tree[i][2]][j+1]|=f[i][j];
            if(s[j+1]=='G')    if(tree[i][3])    f[tree[i][3]][j+1]|=f[i][j];
            if(s[j+1]=='?')
                for(int k=0;k<5;++k)
                    if(tree[i][k])    f[tree[i][k]][j+1]|=f[i][j];
            if(s[j+1]=='*'){
                f[i][j+1]|=f[i][j];
                for(int k=0;k<5;++k)
                    if(tree[i][k])    f[tree[i][k]][j]|=f[i][j];
            }
        }
        for(int j=0;j<5;++j)    f[tree[i][j]][len]|=f[i][len];
    }
    int ans=n;
    for(int i=1;i<=n;++i)
        if(f[pnt[i]][len]==1)    ans--;
    printf("%d\n",ans);
    return 0;
}

/*
A*G?C
3
AGTC
AGTGTC
AGTGC 
*/

 

posted @ 2018-04-03 20:52  Konoset  阅读(240)  评论(0编辑  收藏  举报