[bzoj2780][Spoj8093]Sevenk Love Oimaster_广义后缀自动机
Sevenk Love Oimaster bzoj-2780 Spoj-8093
题目大意:给定$n$个大串和$m$次询问,每次给出一个字符串$s$询问在多少个大串中出现过。
注释:$1\le n\le 10^4$,$1\le q\le 6\cdot 10^4$,$the\ total\ length\ of\ n\ strings\ \le 10^5$,
$the\ total\ length\ of\ q\ question\ strings\le 3.6\times 10^5$。
想法:广义后缀自动机
先对$n$个串建立广义后缀自动机。
后缀自动机上每个节点记录下在多少个串串里出现过,记为$cnt_i$。
然后对于每个询问串,沿着$trans$指针走到当前的$now$节点,输出$cnt_{now}$即可。
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <string> #define N 200010 using namespace std; int n,m,last=1,tot=1,tr[N][26],fa[N],len[N],cnt[N],vis[N]; string s[N],ss; void update(int c) { int v=last,u=++tot; last=u; len[u]=len[v]+1; while(v&&!tr[v][c]) tr[v][c]=u,v=fa[v]; if(!v) fa[u]=1; else { int x=tr[v][c]; if(len[x]==len[v]+1) fa[u]=x; else { int y=++tot; memcpy(tr[y],tr[x],sizeof tr[y]); fa[y]=fa[x]; fa[x]=fa[u]=y; len[y]=len[v]+1; while(v&&tr[v][c]==x) tr[v][c]=y,v=fa[v]; } } } int main() { ios::sync_with_stdio(false); int n,m; cin >> n >> m ; for(int i=1;i<=n;i++) { cin >> s[i] ; int l=s[i].length(); last=1; for(int j=0;j<l;j++) update(s[i][j]-'a'); } for(int i=1;i<=n;i++) { int l=s[i].length(),now=1; for(int j=0;j<l;j++) { now=tr[now][s[i][j]-'a']; int t=now; while(t&&vis[t]!=i) { cnt[t]++; vis[t]=i; t=fa[t]; } } } for(int i=1;i<=m;i++) { cin >> ss ; int l=ss.length(),now=1; for(int j=0;j<l;j++) now=tr[now][ss[j]-'a']; printf("%d\n",cnt[now]); } return 0; }
小结:对后缀自动机的理解好浅啊...
| 欢迎来原网站坐坐! >原文链接<