• HDU5880【AC自动机】


    题意:

    给出n个字符串,再给出一个字符串,把之前出现过的字符串全部变成*

    思路:
    AC自动机,Trie树上存的值是一个字符串的长度,也就是往前的长度,然后倒着处理一遍。

    感想:

    第三题AC自动机,本来就是想脱离模板多练练,虽然之前撒比bug错了一大堆,但是收获很多啊。

    重要的感想有两个方面:

    一:

    在我们solve主串的时候:

    在通过移动失败指针处理后缀串的时候,在这道题里只要找到一个就行了。

    看了网上,主要有两种标记方法(其实类似),其中一种就是通过标记这个位置最长后缀来处理,这样完全可行,然而那个博主的处理方法并不合适,

    那个博主的方法是在通过移动失败指针处理后缀串的时候,还在比较取这个位置的后缀串最大,其实理解的话,我们完全不需要比较啊,理由:这个后缀串本身就是你的子串,何必啊???而且在通过移动失败指针处理后缀串的时候第一个即最长。

    二:

    一开始无脑在线printf,本身就是比较费时的写法,然后就靠评测机抖一抖AC,直接先转变好,一发printf,妥妥的省了一堆时间。

    (三:

    模板还是网赛用用吧???

    //#include <bits/stdc++.h>
    #include<iostream>
    #include<queue>
    #include<string.h>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    
    const int N=1e6+10;
    struct Trie{
        int num;
        Trie *next[27],*fail;
    };
    Trie q[N],*root;
    int tol;
    char word[N],str[N];
    //int latersum[N];//第一种方法
    int flag[N];//第二种方法
    
    Trie* Creat()
    {
         Trie *p;
         p=&q[tol++];
         p->num=0;
         p->fail=NULL;
         for(int i=0;i<26;i++)
            p->next[i]=NULL;
        return p;
    }
    
    void Insert()
    {
        Trie* p=root;
        int len=strlen(str),index;
        for(int i=0;i<len;i++)
        {
            index=str[i]-'a';
            if(p->next[index]==NULL)
                p->next[index]=Creat();
            p=p->next[index];
        }
        p->num=len;
    }
    
    void Build_Ac()
    {
        queue<Trie*>que;
        que.push(root);
        while(!que.empty())
        {
            Trie *p=que.front();que.pop();
            for(int i=0;i<26;i++)
            {
                if(p->next[i]!=NULL)
                {
                    if(p==root)
                        p->next[i]->fail=root;
                    else
                    {
                        Trie* temp=p->fail;
                        while(temp!=NULL)
                        {
                            if(temp->next[i]!=NULL){
                                p->next[i]->fail=temp->next[i];
                                break;
                            }
                            temp=temp->fail;
                        }
                        if(temp==NULL)
                            p->next[i]->fail=root;
                    }
                    que.push(p->next[i]);
                }
            }
        }
    }
    
    void Query()
    {
        int len=strlen(word),index;
    
        Trie *p=root;
        for(int i=0;i<len;i++)
        {
    //        latersum[i]=0;
            flag[i]=0;
            if(!((word[i]>='a'&& word[i]<='z')||(word[i]>='A'&&word[i]<='Z')))
                    continue;
            index=(word[i]>='A'&&word[i]<='Z')?(tolower(word[i])-'a'):(word[i]-'a');
            while(p->next[index]==NULL && p!=root)
                p=p->fail;
            p=p->next[index];
            if(p==NULL)
                p=root;
            Trie *temp=p;
            while(temp!=root)
            {
                if(temp->num){
    //                flag[i]=max(flag[i],temp->num);
                    flag[i]=temp->num;
    //                latersum[i+1]--;
    //                latersum[i-temp->num+1]++;
                    break;//第一个后缀一定是最长的,不需要在转移到别的fail指针
                }
                temp=temp->fail;
            }
        }
    //    int nn=0;//无脑printf,此代码要看天命AC
    //    for(int i=0;i<len;i++)
    //    {
    //        nn+=latersum[i];
    ////        if(nn<=0)
    ////            printf("%c",word[i]);
    ////        else
    //        if(nn>0)
    //            word[i]='*';
    //    }
    //    puts("");
        int nn=0;
        for(int i=len-1;i>=0;i--)
        {
            nn=max(nn,flag[i]);
            if(!nn) continue;
            else{
                word[i]='*';
                nn--;
            }
        }
        printf("%s
    ",word);
    }
    
    int main()
    {
        int T,n;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            tol=0;
            root=Creat();
            while(n--)
            {
                scanf("%s",str);
                Insert();
            }
            getchar();
            Build_Ac();
            gets(word);
            Query();
        }
        return 0;
    }
    
    
    


  • 相关阅读:
    FFT加速多项式乘法C语言版(基2FFT)
    springboot2中@ConfigurationProperties装载yml文件的时候调取出现值为null的解决办法
    LeetCode27-移除元素
    dom4j在解析xml文件的时候将" "解析成空格的解决办法
    LeetCode17- 电话号码的字母组合
    LeetCode19- 删除链表的倒数第N个节点
    LeetCode14- 最长公共前缀
    LeetCode20- 有效的括号
    LeetCode21- 合并两个有序链表
    MySQL单表百万数据记录分页性能优化
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777433.html
Copyright © 2020-2023  润新知