CF 316G3 Good Substrings——广义后缀自动机
题目:http://codeforces.com/contest/316/problem/G3
对询问串和模式串一起建一个后缀自动机,做出在每个串上的 right 集合大小之后枚举自动机上的每个点看看是否合法即可(合法的话,贡献是 len[ cr ] - len[ fa ])。
注意做出拓扑序后用的是 q[ i ] 而不是 i !
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const int N=550005,M=15,K=30; int n,cnt=1,len[N],fa[N],go[N][K],ep[N]; int l[M],r[M],tx[N],q[N],ct[N][M]; ll ans; char s[N]; bool vis[N]; int cz(int p,int w,int bh) { int q=go[p][w], nq=++cnt; len[nq]=len[p]+1; fa[nq]=fa[q]; fa[q]=nq; memcpy(go[nq],go[q],sizeof go[q]); for(;go[p][w]==q;p=fa[p])go[p][w]=nq; return nq; } int ins(int p,int w,int bh) { if(go[p][w]) { int q=go[p][w]; if(len[q]==len[p]+1)return q; return cz(p,w,bh); } 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;return np;} int q=go[p][w]; if(len[q]==len[p]+1)fa[np]=q; else fa[np]=cz(p,w,-1); return np; } void Rsort() { for(int i=1;i<=cnt;i++)tx[len[i]]++; for(int i=2;i<=cnt;i++)tx[i]+=tx[i-1]; for(int i=1;i<=cnt;i++)q[tx[len[i]]--]=i; } bool chk(int cr) { for(int i=1;i<=n;i++) if(ct[cr][i]<l[i]||ct[cr][i]>r[i]) return false; return true; } int main() { scanf("%s",s+1); int d=strlen(s+1); for(int i=1,p=1;i<=d;i++) p=ins(p,s[i]-'a'+1,0), ct[p][0]=1; scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%s%d%d",s+1,&l[i],&r[i]); d=strlen(s+1); for(int j=1,p=1;j<=d;j++) p=ins(p,s[j]-'a'+1,i), ct[p][i]=1; } Rsort(); for(int i=cnt;i;i--) { int cr=q[i], f=fa[q[i]];////q[i] not i!!! for(int j=0;j<=n;j++)ct[f][j]+=ct[cr][j]; } for(int i=2;i<=cnt;i++) if(ct[i][0]&&chk(i)) ans+=len[i]-len[fa[i]]; printf("%lld\n",ans); return 0; }