HDU 5880

思路:AC自动机的模板题。可是这个题目给的数据范围特别大,算一下空间复杂度,直接超内存了。注意这里不要用memset一次性清空数组,超内存是一次性memset数组导致的,将没有用的空间也用上了,于是试了下不一次性memset数组,果断不超了。每一次匹配成功,做出相应标记时,要标记整个匹配的串的范围,最后一遍扫过去即可。详见代码。代码只是提供大致思路。

TLE代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn =  1e6+1;

int trie[maxn][26]; //字典树
int fail[maxn];     //失败时的回溯指针
int cnt = 0;
int dep[maxn];
int vs[maxn];

void init() {

    memset(trie[0],0,sizeof(trie[0]));
    memset(fail,0,sizeof(fail));
    for(int i=0;i<cnt;i++)
        fail[i]=dep[i]=vs[i]=0;
    cnt = 0;
    ///memset(dep,0,sizeof(dep));
    ///memset(vs,0,sizeof(vs));
}

void insertWords(char *s)
{
    int l=strlen(s);
    int root = 0;
    for(int i=0; i<l; i++)
    {
        int next = s[i] - 'a';
        if(!trie[root][next])
            memset(trie[cnt+1],0,sizeof(trie[cnt+1])),
            trie[root][next] = ++cnt;
        root = trie[root][next];
    }
    dep[root]=l;
}
void getFail()
{
    queue <int>q;
    for(int i=0; i<26; i++)     //将第二层所有出现了的字母扔进队列
    {
        if(trie[0][i])
        {
            fail[trie[0][i]] = 0;
            q.push(trie[0][i]);
        }
    }
    while(!q.empty())
    {
        int now = q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(trie[now][i])
            {
                fail[trie[now][i]] = trie[fail[now]][i];
                q.push(trie[now][i]);
            }
            else
                trie[now][i] = trie[fail[now]][i];
        }
    }
}


void query(char *s)
{
    char ss;
    int now = 0,ans = 0;
    int l=strlen(s);
    for(int i=0; i<l; i++)   //遍历文本串
    {
        ss=s[i];
        if('A'<=ss&&ss<='Z') ss+=32;
        else if('a'<=ss&&ss<='z') int kk;
        else continue;
        now = trie[now][ss-'a'];  //从s[i]点开始寻找
        for(int j=now; j; j=fail[j])
        {
            if(dep[j])
            {
                vs[i-dep[j]+1]--,vs[i+1]++;
            }
        }
    }
    int sum=0;
    for(int i=0; i<strlen(s); i++)
    {
        sum+=vs[i];
        if(sum<0) printf("*");
        else printf("%c",s[i]);
    }
    printf("\n");
}

char s[maxn];
int main()
{
    int n,t;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%s",s);
            insertWords(s);
        }
        fail[0] = 0;
        getFail();
        getchar();
        gets(s);
        ///fgets(s, maxn, stdin);
        query(s);
        init();
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值