[Tjoi2016&Heoi2016]字符串
Posted Mafia
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Tjoi2016&Heoi2016]字符串相关的知识,希望对你有一定的参考价值。
[Tjoi2016&Heoi2016]字符串
题目
佳媛姐姐过生日的时候,她的小伙伴从某东上买了一个生日礼物。生日礼物放在一个神奇的箱子中。箱子外边写了一个长为n的字符串s,和m个问题。佳媛姐姐必须正确回答这m个问题,才能打开箱子拿到礼物,升职加薪,出任CEO,嫁给高富帅,走上人生巅峰。每个问题均有a,b,c,d四个参数,问你子串s[a..b]的所有子串和s[c..d]的最长公共前缀的长度的最大值是多少?佳媛姐姐并不擅长做这样的问题,所以她向你求助,你该如何帮助她呢?INPUT
输入的第一行有两个正整数n,m,分别表示字符串的长度和询问的个数。接下来一行是一个长为n的字符串。接下来m行,每行有4个数a,b,c,d,表示询问s[a..b]的所有子串和s[c..d]的最长公共前缀的最大值。1<=n,m<=100,000,字符串中仅有小写英文字母,a<=b,c<=d,1<=a,b,c,d<=nOUTPUT
对于每一次询问,输出答案。
SAMPLE
INPUT
5 5
aaaaa
1 1 1 5
1 5 1 1
2 3 2 3
2 4 2 3
2 3 2 4OUTPUT
1
1
2
2
2
解题报告
$SA$+主席树+二分答案
显然这道题直接用$SA$是不太可行的,所以我们可以考虑把他转化成判定性问题,我们二分一个$mid$,判定该长度是否可行
我们考虑$SA$的用法,若两子串有公共前缀,那么两子串中间的$height$必不为$0$
那么用$RMQ$搞出当前可以扩展二分答案出的子串至最长,然后进行查询
显然我们可以将$Rank$扔到主席树中,再去搞查询
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 using namespace std; 5 inline int read(){ 6 int sum(0); 7 char ch(getchar()); 8 for(;ch<‘0‘||ch>‘9‘;ch=getchar()); 9 for(;ch>=‘0‘&&ch<=‘9‘;sum=sum*10+(ch^48),ch=getchar()); 10 return sum; 11 } 12 int n,m,q; 13 char s[100005]; 14 int t1[100005],t2[100005],t3[100005],buc[100005]; 15 int sa[100005],rank[100005],height[100005],mn[100005][20]; 16 inline void Suffix(){ 17 int i,j,k(0),p(0),*x(t1),*y(t2),*t; 18 for(i=0;i<=m;++i)buc[i]=0; 19 for(i=1;i<=n;++i)++buc[x[i]=s[i]]; 20 for(i=1;i<=m;++i)buc[i]+=buc[i-1]; 21 for(i=n;i>=1;--i)sa[buc[x[i]]--]=i; 22 for(j=1;p<n;j<<=1,m=p){ 23 for(p=0,i=n-j+1;i<=n;++i)y[++p]=i; 24 for(i=1;i<=n;++i) 25 if(sa[i]>j) 26 y[++p]=sa[i]-j; 27 for(i=0;i<=m;++i)buc[i]=0; 28 for(i=1;i<=n;++i)t3[i]=x[y[i]]; 29 for(i=1;i<=n;++i)++buc[t3[i]]; 30 for(i=1;i<=m;++i)buc[i]+=buc[i-1]; 31 for(i=n;i>=1;--i)sa[buc[t3[i]]--]=y[i]; 32 for(t=x,x=y,y=t,x[sa[1]]=1,p=1,i=2;i<=n;++i) 33 x[sa[i]]=((y[sa[i]]==y[sa[i-1]])&&(y[sa[i]+j]==y[sa[i-1]+j]))?p:++p; 34 } 35 for(i=1;i<=n;++i)rank[sa[i]]=i; 36 for(i=1;i<=n;height[rank[i++]]=k) 37 for(k?--k:0,j=sa[rank[i]-1];s[i+k]==s[j+k];++k); 38 } 39 inline void ST(){ 40 for(int i=1;i<=n;++i) 41 mn[i][0]=height[i]; 42 for(int i=1;(1<<i)<=n;++i) 43 for(int j=1;j+(1<<i)-1<=n;++j) 44 mn[j][i]=min(mn[j][i-1],mn[j+(1<<i-1)][i-1]); 45 } 46 int cnt; 47 int rt[100005],lch[2000005],rch[2000005],sum[2000005]; 48 inline void update(int &x,int las,int pos,int l,int r){ 49 x=++cnt; 50 // cout<<x<<‘ ‘<<las<<‘ ‘<<pos<<‘ ‘<<l<<‘ ‘<<r<<endl; 51 lch[x]=lch[las]; 52 rch[x]=rch[las]; 53 sum[x]=sum[las]+1; 54 if(l==r) 55 return; 56 int mid((l+r)>>1); 57 if(pos<=mid) 58 update(lch[x],lch[las],pos,l,mid); 59 else 60 update(rch[x],rch[las],pos,mid+1,r); 61 } 62 inline int query(int x,int y,int ll,int rr,int l,int r){ 63 if(ll<=l&&r<=rr) 64 return sum[y]-sum[x]; 65 int mid((l+r)>>1); 66 if(rr<=mid) 67 return query(lch[x],lch[y],ll,rr,l,mid); 68 if(mid<ll) 69 return query(rch[x],rch[y],ll,rr,mid+1,r); 70 return query(lch[x],lch[y],ll,mid,l,mid)+query(rch[x],rch[y],mid+1,rr,mid+1,r); 71 } 72 int main(){ 73 n=read(),q=read(),m=130; 74 scanf("%s",s+1); 75 Suffix(); 76 ST(); 77 for(int i=1;i<=n;++i) 78 update(rt[i],rt[i-1],rank[i],1,n); 79 while(q--){ 80 int a(read()),b(read()),c(read()),d(read()); 81 int l(1),r(min(b-a+1,d-c+1)),mid,ans=0; 82 int tp(rank[c]); 83 while(l<=r){ 84 mid=(l+r)>>1; 85 int tp1(tp),tp2(tp); 86 for(int i=16;i>=0;--i) 87 if(tp1>=(1<<i)&&mn[tp1-(1<<i)+1][i]>=mid) 88 tp1-=(1<<i); 89 for(int i=16;i>=0;--i) 90 if(tp2+(1<<i)<=n&&mn[tp2+1][i]>=mid) 91 tp2+=(1<<i);//cout<<l<<‘ ‘<<r<<‘ ‘<<mid<<‘ ‘<<tp1<<" "<<tp2<<endl; 92 if(query(rt[a-1],rt[b-mid+1],tp1,tp2,1,n)>0) 93 ans=mid,l=mid+1; 94 else 95 r=mid-1; 96 } 97 printf("%d\n",ans); 98 } 99 }
以上是关于[Tjoi2016&Heoi2016]字符串的主要内容,如果未能解决你的问题,请参考以下文章
Bzoj4556: [Tjoi2016&Heoi2016]字符串 后缀数组
[BZOJ4556][Tjoi2016&Heoi2016]字符串 后缀数组+主席树