码迷,mamicode.com
首页 > 其他好文 > 详细

[AHOI2005] 病毒检测 - Trie,BFS

时间:2020-03-08 22:09:28      阅读:66      评论:0      收藏:0      [点我收藏+]

标签:标记   哈希表   har   一个   +=   过程   int   png   这一   

给定一个模板串,里面带有 * (可以匹配任意一段可以为空的串)和 ? (可以匹配任意一个字母),然后给定 \(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

标签:标记   哈希表   har   一个   +=   过程   int   png   这一   

原文地址:https://www.cnblogs.com/mollnn/p/12445027.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!