bzoj 3277 & bzoj 3473,bzoj 2780 —— 广义后缀自动机
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3277
https://www.lydsy.com/JudgeOnline/problem.php?id=3473
广义后缀自动机:https://www.cnblogs.com/HocRiser/p/9580478.html
像 Trie 树一样处理了重复节点;
基数排序后DP,f 数组求的直接是这个点及其祖先的答案;
开 2e5 就可以,因为每次加入一个字符最多新增2个点。
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=2e5+5; int n,K,cnt=1,go[xn][30],len[xn],fa[xn],vis[xn],tot[xn],lst; ll f[xn]; string s[xn]; int work(int p,int w) { int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1; memcpy(go[nq],go[q],sizeof go[q]); fa[nq]=fa[q]; fa[q]=nq; for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq; return nq; } int ext(int p,int w) { if(go[p][w]) { int q=go[p][w]; if(len[q]==len[p]+1)return q; return work(p,w); } int np=++cnt; len[np]=len[p]+1; for(;p&&!go[p][w];p=fa[p])go[p][w]=np; if(!p)fa[np]=1; else { int q=go[p][w]; if(len[q]==len[p]+1)fa[np]=q; else fa[np]=work(p,w); } return np; } int tax[xn],q[xn],l[xn]; void rsort() { for(int i=1;i<=cnt;i++)tax[len[i]]++; for(int i=1;i<=cnt;i++)tax[i]+=tax[i-1]; for(int i=cnt;i;i--)q[tax[len[i]]--]=i; } char dc[xn]; int main() { scanf("%d%d",&n,&K); for(int i=1;i<=n;i++) { scanf("%s",dc); s[i]=string(dc); l[i]=strlen(dc); lst=1; for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a'); } for(int i=1;i<=n;i++) { int nw=1; for(int j=0;j<l[i];j++) { nw=go[nw][s[i][j]-'a']; for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++; } } rsort(); for(int i=1,x;i<=cnt;i++) f[x=q[i]]=f[fa[x]]+(tot[x]>=K?len[x]-len[fa[x]]:0);// for(int i=1;i<=n;i++) { ll ans=0; int nw=1; for(int j=0;j<l[i];j++) nw=go[nw][s[i][j]-'a'],ans+=f[nw]; printf("%lld ",ans); } puts(""); return 0; }
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2780
几乎完全一样,但忘记写 lst=1 呆了半小时...
代码如下:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; int const xn=2e5+5; int n,m,cnt=1,fa[xn],l[xn],go[xn][30],len[xn],tot[xn],vis[xn],lst; char dc[xn]; string s[xn]; int work(int p,int w) { int nq=++cnt,q=go[p][w]; len[nq]=len[p]+1; memcpy(go[nq],go[q],sizeof go[q]); fa[nq]=fa[q]; fa[q]=nq; for(;p&&go[p][w]==q;p=fa[p])go[p][w]=nq; return nq; } int ext(int p,int w) { if(go[p][w]) { int q=go[p][w]; if(len[q]==len[p]+1)return q; return work(p,w); } int np=++cnt; len[np]=len[p]+1; for(;p&&!go[p][w];p=fa[p])go[p][w]=np; if(!p)fa[np]=1; else { int q=go[p][w]; if(len[q]==len[p]+1)fa[np]=q; else fa[np]=work(p,w); } return np; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%s",dc); l[i]=strlen(dc); s[i]=string(dc); lst=1;//lst=1!! for(int j=0;j<l[i];j++)lst=ext(lst,s[i][j]-'a'); } for(int i=1;i<=n;i++) { int nw=1; for(int j=0;j<l[i];j++) { nw=go[nw][s[i][j]-'a']; for(int p=nw;p&&vis[p]!=i;p=fa[p])vis[p]=i,tot[p]++; } } for(int i=1;i<=m;i++) { scanf("%s",dc); int lth=strlen(dc),nw=1; for(int j=0;j<lth;j++)nw=go[nw][dc[j]-'a']; printf("%d\n",tot[nw]); } return 0; }