码迷,mamicode.com
首页 > 其他好文 > 详细

暑假 D6 T1 substring(AC自动机)

时间:2019-07-15 20:02:48      阅读:100      评论:0      收藏:0      [点我收藏+]

标签:max   string   printf   记录   include   遍历   次数   一个   get   

题目描述

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

输入格式

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

第二行为长为n的文本串

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

输出格式

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

数据范围

对于100%的数据n,Q≤100000,且保证S为长度不超过100000的回文串,且所有的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\n");
        else printf("NO\n");
    }
    return 0;
}
/*
6 3
abdbec
e
bdb
aa
*/

不过好像可以直接用补全的AC自动机,查询就在树上跑文本串,对于每一个节点跳fail,对于要求的S的结尾存下询问标号,遍历到他就记录。

不过好像差不多。

暑假 D6 T1 substring(AC自动机)

标签:max   string   printf   记录   include   遍历   次数   一个   get   

原文地址:https://www.cnblogs.com/sto324/p/11190988.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!