• 暑假 D6 T1 substring(AC自动机)


    题目描述

    给出一个长度为n的文本串,有Q次询问,每次给出一个字符串S,询问S是否在文本串中作为子串出现过

    输入格式

    第一行两个整数n和Q,分别表示文本串长度和询问次数

    第二行为长为n的文本串

    接下来Q行,每行为一个字符串S

    输出格式

    输出Q行对应Q次询问的答案,若出现过则输出YES,否则输出NO

    数据范围

    对于100%的数据n,Q≤100000,且保证s为长度不超过10000的回文串且所有s的总长不超过1000000,保证所有字符都是小写字母

    题解

    看到题目就想起了阿狸的打字机,而且还只是遍历一条路径

    栈的范围没改到崩了可还行

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn=100005;
    const int maxm=1000005;
    int n,m,num,cnt;
    int go[maxm][26],mp[maxn];
    int gogo[maxm][26],fail[maxm];//trie图 
    int in[maxm],size[maxm];
    char s[maxn],t[maxn];
    int head[maxm];
    struct edge{
        int y,next;
    }e[maxm<<1];
    int tr[maxm<<1];
    
    void add1(int len){
        int now=0;
        for(int i=0;i<len;i++){
            int c=s[i]-'a';
            if(!go[now][c]) gogo[now][c]=go[now][c]=++num;
            now=go[now][c];
        }
        mp[++cnt]=now;
    }
    
    void addedge(int x,int y){
        e[++cnt]=(edge){y,head[x]};
        head[x]=cnt;
    }
    
    int q[maxm];
    void get_fail(){
        cnt=0;
        int h=0,tail=0;
        for(int i=0;i<26;i++) if(gogo[0][i]){q[tail++]=gogo[0][i];addedge(0,gogo[0][i]);}
        while(h<tail){
            int x=q[h++];
            for(int i=0;i<26;i++){
                if(!gogo[x][i]) gogo[x][i]=gogo[fail[x]][i];
                else{
                    fail[gogo[x][i]]=gogo[fail[x]][i];
                    addedge(gogo[fail[x]][i],gogo[x][i]);
                    q[tail++]=gogo[x][i];
                }
            }
        }
    }
    
    void dfs(int u){
        in[u]=++cnt;size[u]=1;
        for(int i=head[u];i;i=e[i].next){
            dfs(e[i].y);
            size[u]+=size[e[i].y];
        }
    }
    
    void add(int x,int val){
        for(;x<=cnt;x+=x&-x) tr[x]+=val;
    }
    
    int sum(int x){
        int ret=0;
        for(;x;x-=x&-x) ret+=tr[x];
        return ret;
    }
    
    int main(){
        freopen("substring.in","r",stdin);
        freopen("substring.out","w",stdout);
        scanf("%d%d",&n,&m);
        scanf("%s",t);
        int now=0;
        for(int i=0;i<n;i++){
            int c=t[i]-'a';
            if(!go[now][c]) gogo[now][c]=go[now][c]=++num;
            now=go[now][c];
            //printf("%d ",now);
        }
        for(int i=1;i<=m;i++){
            scanf("%s",s);
            add1(strlen(s));
        }
        get_fail(); 
        cnt=0;
        dfs(0);
        for(int i=1;i<=n;i++) add(in[i],1);
        for(int i=1;i<=m;i++){
            int x=mp[i];//printf("%d ",x);
            if(sum(in[x]+size[x]-1)-sum(in[x]-1)) printf("YES
    ");
            else printf("NO
    ");
        }
        return 0;
    }
    /*
    6 3
    abdbec
    e
    bdb
    aa
    */
    View Code

     直接用补全的AC自动机也可以,最后查询文本串,在每个点一直跳fail,(就是阿狸的暴力

  • 相关阅读:
    JavaScript中trim 方法实现
    面向对象设计的SOLID原则
    对项目的了解差点儿为零?怎样高速上手一个新项目
    计算一个序列的移动平均线序列的模板,可实现均线的均线
    HTML5学习笔记简明版(10):废弃的元素和属性
    Using Swift with Cocoa and Objective-C下载
    实战Java虚拟机之中的一个“堆溢出处理”
    Delphi导出数据的多种方法
    Delphi+DBGrid导出Excel
    delphi try except语句 和 try finally语句用法以及区别
  • 原文地址:https://www.cnblogs.com/sto324/p/11191505.html
Copyright © 2020-2023  润新知