zoukankan      html  css  js  c++  java
  • 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;
    }
    
    
    


  • 相关阅读:
    AppServ设置虚拟主机 及域名连接
    PHPCMS v9 实现首页,列表页,内容页调用点击量方法
    phpcms v9 后台首页 去掉团队信息等版权
    phpcms v9 在当前栏目下获取父栏目与当前栏目的名称与连接
    不是技术牛人,如何拿到国内IT巨头的Offer
    解决phpcms V9缩略图模糊的方法
    apache、nginx、iis 全球分布
    获取屏幕宽度、浏览器宽度、网页高度,宽度信息
    21个适合扁平化设计的创意超链接效果
    javascript模拟鼠标双击事件
  • 原文地址:https://www.cnblogs.com/keyboarder-zsq/p/6777433.html
Copyright © 2011-2022 走看看