标签:pen namespace ac自动机 dde std trie图 出现 trie else
给出一个长度为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\n"); else printf("NO\n"); } return 0; } /* 6 3 abdbec e bdb aa */
标签:pen namespace ac自动机 dde std trie图 出现 trie else
原文地址:https://www.cnblogs.com/sto324/p/11191505.html