[后缀自动机 阈值] LOJ#6031. 「雅礼集训 2017 Day1」字符串
2018-01-24 14:05
495 查看
对 k 阈值
如果 k≤S
枚举询问串的每个子串,在后缀自动机上找到对应的节点就可以了
O(qkk2logn)
如果 k>S
枚举询问串的前缀,找到对应节点,每个和这个前缀相关的询问是这个前缀的后缀,在fail树上倍增
O(qk(k+mlogn))
这个log我卡不掉,只能对着数据卡常了
如果 k≤S
枚举询问串的每个子串,在后缀自动机上找到对应的节点就可以了
O(qkk2logn)
如果 k>S
枚举询问串的前缀,找到对应节点,每个和这个前缀相关的询问是这个前缀的后缀,在fail树上倍增
O(qk(k+mlogn))
这个log我卡不掉,只能对着数据卡常了
#include <cstdio> #include <iostream> #include <algorithm> #include <vector> #include <cmath> #include <cstring> #include <map> using namespace std; typedef long long ll; const int N=200010; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline void read(int &x){ char c=nc(); x=0; for(;c>'9'||c<'0';c=nc());for(;c>='0'&&c<='9';x=x*10+c-'0',c=nc()); } inline void read(char *a){ char c=nc(); int x=0; for(;c>'z'||c<'a';c=nc());for(;c>='a'&&c<='z';a[++x]=c,c=nc()); } int n,m,q,k,S,l ,r ; char s ; int p=1,cnt=1,nxt [30],fail ,len ,val ; inline void extend(int c){ int np=++cnt; len[np]=len[p]+1; val[np]=1; while(p && !nxt[p][c]) nxt[p][c]=np,p=fail[p]; if(!p) fail[np]=1; else{ int q=nxt[p][c]; if(len[q]==len[p]+1) fail[np]=q; else{ int nq=++cnt; len[nq]=len[p]+1; memcpy(nxt[nq],nxt[q],sizeof(nxt[q])); fail[nq]=fail[q]; fail[q]=fail[np]=nq; while(p && nxt[p][c]==q) nxt[p][c]=nq,p=fail[p]; } } p=np; } int id ,t ,fa [20]; inline void Pre(){ for(int i=1;i<=cnt;i++) t[len[i]]++; for(int i=1;i<=cnt;i++) t[i]+=t[i-1]; for(int i=1;i<=cnt;i++) id[t[len[i]]--]=i; for(int i=cnt;i;i--) val[fail[id[i]]]+=val[id[i]]; for(int i=1;i<=cnt;i++){ int x=id[i]; fa[x][0]=fail[x]; for(int j=1;j<=10;j++) fa[x][j]=fa[fa[x][j-1]][j-1]; } } const int MAX=316*320+320; int ans ; vector<int> M[MAX]; int ap[MAX],flg[MAX],pr[320][N>>1]; inline int calc(pair<int,int> A,int L,int R){ int g=A.first*320+A.second; if(flg[g]){ int cur=flg[g]; return pr[cur][R]-pr[cur][L-1]; } vector<int> c=M[A.first*320+A.second]; return upper_bound(c.begin(),c.end(),R)-lower_bound(c.begin(),c.end(),L); } void PutAns(ll x){ if(x>=10) PutAns(x/10); putchar(x%10+'0'); } inline void Case1(){ for(int i=1;i<=m;i++) ap[l[i]*320+r[i]]++; int S=316,cc=0; for(int l=1;l<=k;l++) for(int r=l;r<=k;r++) if(ap[l*320+r]>S){ flg[l*320+r]=++cc; for(int i=1;i<=m;i++) pr[cc][i]=pr[cc][i-1]+(::l[i]==l && ::r[i]==r); } for(int i=1;i<=m;i++) M[l[i]*320+r[i]].push_back(i); while(q--){ int L,R; read(s); read(L); read(R); L++; R++; ll ans=0; for(int l=1;l<=k;l++){ int cur=1; for(int r=l;r<=k;r++){ if(!nxt[cur][s[r]-'a']) break; cur=nxt[cur][s[r]-'a']; ans+=val[cur]*calc(make_pair(l,r),L,R); } } PutAns(ans); putchar('\n'); } } vector<pair<int,int> > Q ; inline void Case2(){ for(int i=1;i<=m;i++) Q[r[i]].push_back(make_pair(l[i],i)); while(q--){ read(s); int L,R; read(L); read(R); L++; R++; int cur=1,cnt=0; ll ans=0; for(int r=1;r<=k;r++){ while(cur && !nxt[cur][s[r]-'a']) cur=fail[cur],cnt=len[cur]; if(!cur){ cur=1; cnt=0; continue; } cur=nxt[cur][s[r]-'a']; cnt++; for(auto u : Q[r]){ int l=u.first,t=u.second; if(r-l+1>cnt || t<L || t>R) continue; int c=cur; for(int i=10;~i;i--) if(len[fa[c][i]]>=r-l+1) c=fa[c][i]; ans+=val[c]; } } PutAns(ans); putchar('\n'); } } int main(){ freopen("1.in","r",stdin); freopen("1.out","w",stdout); read(n); read(m); read(q); read(k); read(s); for(int i=1;i<=n;i++) extend(s[i]-'a'); Pre(); for(int i=1;i<=m;i++) read(l[i]),read(r[i]),l[i]++,r[i]++; k<=310?Case1():Case2(); return 0; }
相关文章推荐
- [后缀自动机][阈值] LOJ #6031. 「雅礼集训 2017 Day1」字符串
- [后缀自动机][树上启发式合并] LOJ #6041. 「雅礼集训 2017 Day7」事情的相似度
- [ 后缀自动机 树上启发式合并 线段树 树状数组 ] [ 雅礼集训 2017 Day7 ] LOJ#6041
- [后缀自动机 DP] LOJ#6071. 「2017 山东一轮集训 Day5」字符串
- #6029. 「雅礼集训 2017 Day1」市场--线段树区间更新
- LibreOJ#6030. 「雅礼集训 2017 Day1」矩阵
- loj6030 「雅礼集训 2017 Day1」矩阵
- #6029. 【雅礼集训 2017 Day1】市场
- [线段树][简单复杂度分析]LOJ#6029. 「雅礼集训 2017 Day1」市场
- #6030. 【雅礼集训 2017 Day1】矩阵
- loj 6030「雅礼集训 2017 Day1」矩阵
- 「6月雅礼集训 2017 Day1」说无可说
- 「6月雅礼集训 2017 Day1」看无可看
- loj6029 「雅礼集训 2017 Day1」市场
- [广义后缀自动机] BZOJ 3473 字符串 & BZOJ 3277 串 & Codeforces 204E #129 (Div. 1) E. Little Elephant and Strings
- 2017 暑假艾教集训 day10 AC自动机+马拉车+后缀数组 +kmp
- hdu 4416 后缀自动机 问在S中有多少个不同子串满足它不是s1~sn中任意一个字符串的子串
- hdu 4416 后缀自动机 求一个字符串中出现的不同子串的个数(去除一些其他字符串的子串)
- 【BZOJ-4180】字符串计数 后缀自动机 + 矩阵乘法
- SPOJ 1812 Longest Common Substring II 后缀自动机求多字符串最长公共子串