一个初步的想法是我们枚举重复子串的长度\(L\)。然后跑一遍SA。然后我们枚举一个点\(i\),令他的对应点为\(i+L\),然后求出这两个点的LCP和LCS的长度答案就是这个点的答案就是\((len(LCP)+len(LCS)+L-1)/L\)。这个可以用跟\(EXKMP\)的类似的方法证明。

但是这样会T。

那么如何优化?我们在\(1,1+L,1+L*2...\)这些位置设置关键点(这个方法比较常见)。然后枚举每一个点改成每一个关键点。这样为什么会对?当我们对一个不是关键点的点求\(LCP\)和\(LCS\)时。如果\(LCP\)或\(LCS\)过关键点,那么和从关键点求\(LCS\),和\(LCP\)没有区别。如果不过时,那么这两个串就不连在一起,对答案没有贡献。

设置了关键点之后,复杂度变成了调和级数级别。

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<cmath>
  5. #include<algorithm>
  6. using namespace std;
  7. const int N=100100;
  8. int ans,T,n;
  9. struct SA{
  10. int c[N],x[N],y[N],m,sa[N],rk[N],height[N],mn[N][20];
  11. char s[N];
  12. void get_sa(){
  13. for(int i=1;i<=m;i++)c[i]=0;
  14. for(int i=1;i<=n;i++)c[x[i]=s[i]]++;
  15. for(int i=1;i<=m;i++)c[i]+=c[i-1];
  16. for(int i=n;i>=1;i--)sa[c[x[i]]--]=i;
  17. for(int k=1;k<=n;k<<=1){
  18. int num=0;
  19. for(int i=n-k+1;i<=n;i++)y[++num]=i;
  20. for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k;
  21. for(int i=1;i<=m;i++)c[i]=0;
  22. for(int i=1;i<=n;i++)c[x[i]]++;
  23. for(int i=1;i<=m;i++)c[i]+=c[i-1];
  24. for(int i=n;i>=1;i--)sa[c[x[y[i]]]--]=y[i],y[i]=0;
  25. for(int i=1;i<=n;i++)swap(x[i],y[i]);
  26. x[sa[1]]=1;num=1;
  27. for(int i=2;i<=n;i++)
  28. x[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
  29. if(n==num)break;
  30. m=num;
  31. }
  32. }
  33. void get_height(){
  34. int k=0;
  35. for(int i=1;i<=n;i++)rk[sa[i]]=i;
  36. for(int i=1;i<=n;i++){
  37. if(rk[i]==1)continue;
  38. if(k)k--;
  39. int j=sa[rk[i]-1];
  40. while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
  41. height[rk[i]]=k;
  42. }
  43. }
  44. void pre_work(){
  45. for(int i=1;i<=n;i++)mn[i][0]=height[i];
  46. int len=log2(n);
  47. for(int j=1;j<=len;j++)
  48. for(int i=1;i+(1<<j)-1<=n;i++)
  49. mn[i][j]=min(mn[i][j-1],mn[i+(1<<j-1)][j-1]);
  50. }
  51. int getlcp(int l,int r){
  52. if(l>r)swap(l,r);
  53. l++;
  54. // cout<<l<<" "<<r<<"aaaaa"<<endl;
  55. int len=log2(r-l+1);
  56. return min(mn[l][len],mn[r-(1<<len)+1][len]);
  57. }
  58. }A,B;
  59. int read(){
  60. int sum=0,f=1;char ch=getchar();
  61. while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
  62. while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
  63. return sum*f;
  64. }
  65. int main(){
  66. T=read();
  67. while(T--){
  68. n=read();
  69. ans=0;
  70. A.m=B.m=122;
  71. for(int i=1;i<=n;i++)cin>>A.s[i],B.s[n-i+1]=A.s[i];
  72. A.get_sa();A.get_height();A.pre_work();
  73. B.get_sa();B.get_height();B.pre_work();
  74. for(int i=1;i<=n;i++)
  75. for(int j=1;j+i<=n;j+=i)
  76. ans=max(ans,(A.getlcp(A.rk[j],A.rk[j+i])+B.getlcp(B.rk[n-j+1],B.rk[n-j-i+1])+i-1)/i);
  77. printf("%d\n",ans);
  78. }
  79. return 0;
  80. }

SP687 REPEATS - Repeats(后缀数组)的更多相关文章

  1. SPOJ 687 Repeats(后缀数组+ST表)

    [题目链接] http://www.spoj.com/problems/REPEATS/en/ [题目大意] 求重复次数最多的连续重复子串的长度. [题解] 考虑错位匹配,设重复部分长度为l,记s[i ...

  2. 【SPOJ – REPEATS】 后缀数组【连续重复子串】

    字体颜色如何 字体颜色 SPOJ - REPEATS 题意 给出一个字符串,求重复次数最多的连续重复子串. 题解 引自论文-后缀数组--处理字符串的有力工具. 解释参考博客 "S肯定包括了字 ...

  3. SPOJ REPEATS Repeats (后缀数组 + RMQ:子串的最大循环节)题解

    题意: 给定一个串\(s\),\(s\)必有一个最大循环节的连续子串\(ss\),问最大循环次数是多少 思路: 我们可以知道,如果一个长度为\(L\)的子串连续出现了两次及以上,那么必然会存在\(s[ ...

  4. SPOJ Repeats(后缀数组+RMQ-ST)

    REPEATS - Repeats no tags  A string s is called an (k,l)-repeat if s is obtained by concatenating k& ...

  5. SPOJ REPEATS 后缀数组

    题目链接:http://www.spoj.com/problems/REPEATS/en/ 题意:首先定义了一个字符串的重复度.即一个字符串由一个子串重复k次构成.那么最大的k即是该字符串的重复度.现 ...

  6. POJ - 2406 ~SPOJ - REPEATS~POJ - 3693 后缀数组求解重复字串问题

    POJ - 2406 题意: 给出一个字符串,要把它写成(x)n的形式,问n的最大值. 这题是求整个串的重复次数,不是重复最多次数的字串 这题很容易想到用KMP求最小循环节就没了,但是后缀数组也能写 ...

  7. SPOJ - REPEATS Repeats (后缀数组)

    A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed strin ...

  8. spoj687 REPEATS - Repeats (后缀数组+rmq)

    A string s is called an (k,l)-repeat if s is obtained by concatenating k>=1 times some seed strin ...

  9. SPOJ - REPEATS —— 后缀数组 重复次数最多的连续重复子串

    题目链接:https://vjudge.net/problem/SPOJ-REPEATS REPEATS - Repeats no tags  A string s is called an (k,l ...

随机推荐

  1. CorelDRAW设计制作超漂亮的3D立体字效果实例教程

    第一.打上招聘两个字,选择一个喜欢的字体,如下. 第二.把字体转曲,等待下一步编辑曲线做好准备,如下. 第三.选择形状工具,编辑字体形状,根据自己需要可任意编辑,如下. 第四.适当画一些装饰素材,比如 ...

  2. ZBrush 笔刷的基础参数

    ZBrush®中的笔刷基本参数主要包括3个:Draw Size(绘制大小).Focal Shift(焦点衰减)和Z Intensity(深度强度),通常使用这3个基本参数对笔刷进行调整. 在视图文档区 ...

  3. 最近邻插值法&线性插值&双线性插值&三线性插值

    最近邻插值法nearest_neighbor是最简单的灰度值插值.也称作零阶插值,就是令变换后像素的灰度值等于距它最近的输入像素的灰度值. 造成的空间偏移误差为像素单位,计算简单,但不够精确.但当图像 ...

  4. IOS - IOS之同步请求、异步请求、GET请求、POST请求(转载)

    转载:http://www.open-open.com/lib/view/open1355055986679.html 1.同步请求可以从因特网请求数据,一旦发送同步请求,程序将停止用户交互,直至服务 ...

  5. freeswitch 编码协商

    编辑 /usr/local/freeswitch/conf/sip_profiles/internal.xml 添加注释     <param name="inbound-zrtp-p ...

  6. 中山纪念中学培训杂题(难的都不在这里面qwq)

    来中山纪中半个月了,差不多就要结束了, 写一些之前考试能更正的题解吧,还有一些不是给人做的(比如IOI2018互测.. 备注:我不会的就没有放上来了,所有数学有关的基本上都死了. 所以这里的题目都是相 ...

  7. 20121124.Nodejs异步式I/O与事件式编程

    异步: 你请人吃饭,准备一起去的.结果那人刚好有事,让你先去点菜,你去点好菜,他忙完就来了,这就是异步的优势(不耽误事!)同步: 就是,你必须等那个人忙完了,才一起去(浪费时间) 理解来源于群友&qu ...

  8. Jquery学习总结(4)——高效Web开发的10个jQuery代码片段

    在过去的几年中,jQuery一直是使用最为广泛的JavaScript脚本库.今天我们将为各位Web开发者提供10个最实用的jQuery代码片段,有需要的开发者可以保存起来. 1.检测Internet ...

  9. [terry笔记]python购物程序

    如下是一个购物程序: 先输入工资,显示商品列表,购买,quit退出,最后格式化输出所买的商品. count = 0 while True: #做一个循环判断,如果输入的不是数字,基于提示,三次后退出 ...

  10. Xdoclet + Ant自己主动生成Hibernate配置文件

    在使用Hibernate的时候,过多的Hibernate配置文件是一个让人头疼的问题. 近期接触了Xdoclet这个工具. 它实际上就是一个自己主动代码生成的工具.Xdoclet不能单独执行,必须搭配 ...