HDU5880 Family View(AC自动机)

链接:http://acm.hdu.edu.cn/showproblem.php?pid=5880

题意:给定N个串,一个长文本,把那N个串在长文本里出现的部分用×代替。

思路:把N个串放到AC自动机上然后在结点标记上串长,接着把长文本放到自动机上去匹配,匹配到了就替换掉。

至于替换的方法,不用暴力的去修改,只要同类似括号匹配的方式打上标记就好了。要注意2种情况的处理

1:   N个串种有 abcd,bcde这种交叉的情况

2:  N个串有 abcd bc这种包含的情况

然后,千万不要memset整个数组,因为测评鸡算内存只会算用过的,一memset就算全用过了,会爆内存,要用一个就初始化一个。

代码:

#include <bits/stdc++.h>

using namespace std;

#define fur(i,a,b) for(int i=(a);i<=(b);i++)
#define furr(i,a,b) for(int i=(a);i>=(b);i--)
#define cl(a) memset((a),0,sizeof(a))

typedef long long ll;

const int maxsz = 1000000;

const int maxn = 1010000;
int cg[maxn];

char str[maxsz+10];	

struct AC
{
    struct Node
    {
        int fail,cnt,next[26];
    }node[maxn+10];

    int sz;
    queue<int>q;

    void init(){
        sz = 0;
        newnode();
        while(!q.empty()) q.pop();
    }

    int newnode(){
        cl(node[sz].next);
        node[sz].fail = 0;
        node[sz].cnt = 0;
        return sz++;
    }
    
    void insert(char *s){
        int len = strlen(s);
        int now = 0;
        for(int i = 0; i < len; ++i){
            char c = s[i];
            if(!node[now].next[c-'a'])
                node[now].next[c-'a'] = newnode();
            now = node[now].next[c-'a'];
        }
        node[now].cnt = len;
    }

    void build(){
        node[0].fail = -1;
        q.push(0);
        while(!q.empty()){
            int u = q.front();
            q.pop();
            fur(i,0,25){
                if(node[u].next[i]){
                    if(u == 0)
                        node[node[u].next[i]].fail = 0;
                    else{
                        int v = node[u].fail;
                        while(v!=-1){
                            if(node[v].next[i]){
                                node[node[u].next[i]].fail = node[v].next[i];
                                break;
                            }
                            v = node[v].fail;
                        }
                        if(v == -1) node[node[u].next[i]].fail = 0;
                    }
                    q.push(node[u].next[i]);
                }
            }
        }
    }

    void getret(int u, int i){
        while(u){
            if(node[u].cnt){
                cg[i+1]++;
                cg[i-node[u].cnt+1]--;
            }
            u = node[u].fail;
        }
    }

    void match(char *s){
        cl(cg);
        int len = strlen(s);
        int now = 0;
        for(int i = 0; i < len; ++i){
            int idx;
            if(s[i]>='A'&&s[i]<='Z') idx=s[i]-'A';
            else if(s[i]>='a'&&s[i]<='z') idx=s[i]-'a';
            else{
                now = 0;
                continue;
            }
            if(node[now].next[idx])
                now = node[now].next[idx];
            else{
                int u = node[now].fail;
                while(u!=-1 && !node[u].next[idx]) u = node[u].fail;
                if(u == -1) now = 0;
                else now = node[u].next[idx];
            }
            getret(now,i);
        }

        int tmp = 0;

        for(int i = 0; i < len; ++i){
            tmp+=cg[i];
            if(tmp<0) putchar('*');
            else putchar(s[i]); 
        }
        puts("");
    }

}ac;


int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        ac.init();
        int n;
        scanf("%d",&n);
        while(n--){
            scanf("%s",str);
            ac.insert(str);
        }
        ac.build();
        getchar();
        gets(str);
        ac.match(str);
    }
    return 0;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值