[AHOI2005] 病毒检测 - Trie,BFS

Posted mollnn

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AHOI2005] 病毒检测 - Trie,BFS相关的知识,希望对你有一定的参考价值。

给定一个模板串,里面带有 * (可以匹配任意一段可以为空的串)和 ? (可以匹配任意一个字母),然后给定 (n) 个询问串,问有多少询问串不能匹配。(n leq 500, len leq 1000)

技术图片

Solution

对所有询问串建立字典树,然后考虑一个 BFS 过程,状态表示为 ((i,j)),即模板串正要处理第 (i) 个字符,而字典树上走到了 (j) 位置,然后讨论模板串的这一位来转移

  • 如果模板串的这一位是字母,则模板串走一位,结点走对应字母的转移边
  • 如果模板串的这一位是 ?,则模板串走一位,结点走所有字母的转移边
  • 如果模板串的这一位是 *,则
    • 模板串不走,结点走所有字母的转移边
    • 模板串走一位,结点不走

这样就涵盖了所有的转移方法

每走到一个节点,如果 (i=n+1),我们就把 (j) 这个节点打上标记

最后统计所有的打标记的结点中包含了多少个询问串的结束位置即可

为了优化效率,当一个点被打过标记后,下次再走到这个点就直接跳过;走过的状态搞个哈希表记录一下,再走时候直接弹掉

用了双哈希

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;
int n,m,str[N],ch[N][4],fg[N],val[N],ind=1;
char buf[N];
const int mod1 = 492837465, mod2 = 400000007;
bitset <mod1> b1;
bitset <mod2> b2;
int gen1(int i,int j) {
    return (1ll*j*31415926+i)%mod1;
}
int gen2(int i,int j) {
    return (1ll*j*998244353+i)%mod2;
}

struct status {int i,j;};

int tr(char c) {
    if(c=='A') return 0;
    if(c=='C') return 1;
    if(c=='T') return 2;
    if(c=='G') return 3;
}

signed main() {
    ios::sync_with_stdio(false);
    scanf("%s",buf+1);
    n=strlen(buf+1);
    for(int i=1;i<=n;i++) {
        if(buf[i]=='A') str[i]=0;
        if(buf[i]=='C') str[i]=1;
        if(buf[i]=='T') str[i]=2;
        if(buf[i]=='G') str[i]=3;
        if(buf[i]=='?') str[i]=4;
        if(buf[i]=='*') str[i]=5;
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++) {
        scanf("%s",buf+1);
        int len=strlen(buf+1);
        int p=1;
        for(int j=1;j<=len;j++) {
            int x=tr(buf[j]);
            if(ch[p][x]==0) ch[p][x]=++ind;
            p=ch[p][x];
        }
        val[p]++;
    }
    queue <status> q;
    q.push({1,1});
    while(q.size()) {
        status p=q.front();
        q.pop();
        int i=p.i, j=p.j;
        if(b1[gen1(i,j)]&&b2[gen2(i,j)]) continue;
        b1[gen1(i,j)]=1;
        b2[gen2(i,j)]=1;
        if(i==n+1) {
            fg[j]=1;
        }
        else if(!fg[j] && j) {
            if(str[i]<4) {
                q.push({i+1,ch[j][str[i]]});
            }
            if(str[i]==4) {
                if(ch[j][0]) q.push({i+1,ch[j][0]});
                if(ch[j][1]) q.push({i+1,ch[j][1]});
                if(ch[j][2]) q.push({i+1,ch[j][2]});
                if(ch[j][3]) q.push({i+1,ch[j][3]});
            }
            if(str[i]==5) {
                if(ch[j][0]) q.push({i,ch[j][0]});
                if(ch[j][1]) q.push({i,ch[j][1]});
                if(ch[j][2]) q.push({i,ch[j][2]});
                if(ch[j][3]) q.push({i,ch[j][3]});
                q.push({i+1,j});
            }
        }
    }
    int ans=0;
    for(int i=1;i<=ind;i++) ans+=fg[i]*val[i];
    cout<<m-ans;
}

以上是关于[AHOI2005] 病毒检测 - Trie,BFS的主要内容,如果未能解决你的问题,请参考以下文章

bzoj1966: [Ahoi2005]VIRUS 病毒检测

[bzoj1966][Ahoi2005][VIRUS 病毒检测] (字符串dp)

字符串模式匹配——病毒检测

字符串模式匹配——病毒检测

BZOJ 1968: [Ahoi2005]COMMON 约数研究

[AHOI2005] SHUFFLE 洗牌