SuffixArray
来源:互联网 发布:人工智能简介ppt英文 编辑:程序博客网 时间:2024/06/02 05:55
后缀数组。
https://vjudge.net/contest/203023#overview
大约使用基数排序实现的
DC3比较麻烦就先不学了。
Hash+直接排序的方法在10行内完成。
复杂度为
算是也可以用吧。
Problem C
求不同的子串个数。
根据SA的定义,可以比较简单地求出重复的子串个数,即Height值的和。
Code
struct SA{ int Ht[M<<1],Rk[M<<1],sa[M]; int C[M]; void Solve(){ int *x=Rk,*y=Ht; memset(Cnt,0,sizeof(Cnt)); memset(Rk,0,sizeof(Rk)); memset(Ht,0,sizeof(Ht)); REP(i,0,n)Cnt[x[i]=C[i]]++; REP(i,1,M)Cnt[i]+=Cnt[i-1]; REP(i,0,n)sa[--Cnt[x[i]]]=i; for(int k=1;k<=n;k<<=1){ int p=0; REP(i,0,n)Cnt[x[sa[i]]]=i+1; REP(i,n-k,n)y[p++]=i; REP(i,0,n)if(sa[i]>=k)y[p++]=sa[i]-k; DREP(i,n-1,-1)sa[--Cnt[x[y[i]]]]=y[i]; swap(x,y); x[sa[0]]=1; REP(i,1,n)x[sa[i]]=x[sa[i-1]]+ (y[sa[i-1]]!=y[sa[i]] || y[sa[i-1]+k]!=y[sa[i]+k]); } int p=0,j; memset(Rk,0,sizeof(Rk)); REP(i,0,n)Rk[sa[i]]=i; REP(i,0,n)if(j=Rk[i]){ if(p)p--;j=sa[j-1]; while(C[i+p]==C[j+p])p++; Ht[Rk[i]]=p; } Ht[0]=INF; } LL SumH(){ LL Res=0; REP(i,1,n)Res+=Ht[i]; return Res; }}SA;
Problem D
最长回文子串的SA写法。
将原串改为str+‘$’+rev(str)。
分类讨论求某两个位置的LCP。
ST表求RMQ得LCP。
Code
struct SA{ int Ht[M<<1],Rk[M<<1],sa[M],RMQ[M][K]; char C[M]; int LCP(int l,int r){ if(l>r)swap(l,r); l++;int k=Nm[r-l+1];//Nm[i]=log2i return min(RMQ[l][k],RMQ[r-(1<<k)+1][k]); } void ReBuild(){ REP(i,0,n)RMQ[i][0]=Ht[i]; REP(k,1,K)REP(i,0,n)if((j=i+(1<<k-1))<n){ RMQ[i][k]=min(RMQ[i][k-1],RMQ[j][k-1]); }else break; } void Answer(){ int Ans=0,Pos=-1; REP(i,0,m){ int l=Query(Rk[i],Rk[n-i-1]); if(chkmax(Ans,(l<<1)-1))Pos=i-l+1; } REP(i,1,m)if(C[i]==C[i-1]){ int l=Query(Rk[i],Rk[n-i]); if(chkmax(Ans,l<<1))Pos=i-l; } REP(i,Pos,Pos+Ans)putchar(C[i]); puts(""); }}SA;
Problem F
最大连续重复次数子串,字典序最小。
枚举长度,那么该串一定包含相邻该长度距离的两个字符。
分别求这两个字符向前向后的LCP,
即可得到重复次数,然后再通过对Rank值的RMQ求到字典序最小。
加了一些其他的优化。
Code
inline int Cmp(const int &a,const int &b){ return SA1.Rk[a]<SA1.Rk[b]?a:b;}int RKQ[M][K];inline int Query(int l,int r){ int k=Nm[r-l+1]; return Cmp(RKQ[l][k],RKQ[r-(1<<k)+1][k]);}void Answer(){ int j; REP(k,1,K) REP(i,0,n) if((j=i+(1<<k-1))<n) RKQ[i][k]=Cmp(RKQ[i][k-1],RKQ[j][k-1]); int Ans=1,Pos=SA1.sa[0],Len=1; REP(Lth,1,(n>>1)+1){ for(int i=0;i+Lth<n;){ int x,y=0; if(SA1.C[i]==SA1.C[i+Lth]){ x=SA2.LCP(n-i-1,n-i-Lth-1),y=SA1.LCP(i,i+Lth); int Tmp=(x+y-1)/Lth+1; if(Tmp>=Ans){ int Ltp=Tmp*Lth,ps=Query(i-x+1,i+y+Lth-Ltp); if(Ans==Tmp){if(SA1.Rk[ps]<SA1.Rk[Pos])Pos=ps,Len=Ltp;} else Ans=Tmp,Pos=ps,Len=Ltp; } } i+=max(Lth,y); } } printf("Case %d: ",++Case); REP(i,Pos,Pos+Len)putchar(SA1.C[i]); puts("");}
Problem G
最长公共子串。
即分属不同子串的相邻两个串的最大Height值。
Code
struct SA{ void Answer(){ int Ans=0; REP(i,1,n)if(Ans<Ht[i] && ((sa[i-1]<m)!=(sa[i]<m)) ) Ans=Ht[i]; printf("%d\n",Ans); }}SA;int main(){ scanf("%s",SA.C); SA.C[m=strlen(SA.C)]='$'; scanf("%s",SA.C+m+1); n=strlen(SA.C); SA.Solve(); SA.Answer(); return 0;}
Problem L
求一段子串的不同子串的个数。
在询问时保证相邻两个串的字典序,求其LCP并减去。
Code
#define IN(x) (l<=x && x<=r) void Answer(){ int l,r; scanf("%d%d",&l,&r);l--,r--; int Len=r-l+1,Ans=Len*(Len+1)>>1,Lt=-1; REP(i,0,n)if(IN(sa[i])){ if(Lt==-1)Lt=i; else{ int Tmp=LCP(Lt,i); int la=r-sa[Lt]+1,lb=r-sa[i]+1; Ans-=min(min(la,lb),Tmp); if(la<lb || Tmp<lb)Lt=i; if(!(--Len))break; } } printf("%d\n",Ans); }
Problem N
求
不会写就暴力。
二分答案,然后二分当前区间,求Rk最小值判断是否成立。
int Tmp; bool Check(int Len,int i){ if(!Len)return 1; int a,Lt,Rt,l,r; a=Lt=Rt=Rk[i]; l=0,r=a-1; while(l<=r){ int Mid=l+r>>1; if(Query(RMQ,Mid+1,a)>=Len)Lt=Mid,r=Mid-1; else l=Mid+1; } l=a+1,r=n; while(l<=r){ int Mid=l+r>>1; if(Query(RMQ,a+1,Mid)>=Len)Rt=Mid,l=Mid+1; else r=Mid-1; } Tmp=Query(MK,Lt,Rt); return Tmp<i; } void Answer(){ for(int i=0;i<n;){ int l=0,r=n,Res=0; while(l<=r){ int Mid=l+r>>1; if(Check(Mid,i))Res=Mid,l=Mid+1; else r=Mid-1; } if(!Res)printf("-1 %d\n",C[i]),i++; else Check(Res,i),printf("%d %d\n",Res,Tmp),i+=Res; } }
然后正常的写法应该是单调栈。
当
阅读全文
0 0
- SuffixArray
- Origin SuffixArray
- SuffixArray学习小记
- 后缀数组(SuffixArray) 学习笔记
- [ACM模板]SuffixArray后缀数组
- bzoj1031[JSOI2007]字符加密Cipher——SuffixArray
- 【SuffixArray】bzoj1717 [Usaco2006 Dec] Milk Patterns 产奶的模式
- 习题2-3
- python第二天基础
- matlab文字标注
- Jupyter Notebook激活conda环境
- vue2.0集成ueditor以及图片上传,视频上传总结
- SuffixArray
- JQUERY ajax 上传图片 php CI
- 51NOD 1062 序列中的最大数
- 计算机基础知识(一):计算机网络
- Android 微信支付集成
- 网页播放rtmp流
- Double类型做加减乘除精度缺失问题
- nginx禁止访问.git文件的设置(nginx过滤.git文件夹)
- json转数组