题目的Source好有趣。

我们求出SA,然后求出每一个后缀中与前面本质不同的字符串的个数。

然后二分求出当前的字符串。

然后就是正反两次后缀数组求LCP的裸题了。

要注意,这时两个串的起点可能会相同,所以需要判掉。

无论读入还是输出都有可能爆long long,要注意

  1. #include <cstdio>
  2. #include <cstring>
  3. #include <iostream>
  4. #include <algorithm>
  5. using namespace std;
  6. #define F(i,j,k) for (int i=j;i<=k;++i)
  7. #define D(i,j,k) for (int i=j;i>=k;--i)
  8. #define maxn 200500
  9. #define inf 0x3f3f3f3f
  10. #define ll long long
  11.  
  12. int _log2[maxn];
  13.  
  14. struct Suffix_Array{
  15. int s[maxn],cnt[maxn],tmp[maxn],sa[maxn],h[maxn],rk[maxn];
  16. int st[maxn][21];
  17. ll pre[maxn],Sum;
  18. void build(int n,int m)
  19. {
  20. n++; int i,j,k;
  21. F(i,0,2*n+5) sa[i]=tmp[i]=h[i]=rk[i]=0;
  22. F(i,0,m-1) cnt[i]=0;
  23. F(i,0,n-1) cnt[rk[i]=s[i]]++;
  24. F(i,1,m-1) cnt[i]+=cnt[i-1];
  25. F(i,0,n-1) sa[--cnt[rk[i]]]=i;
  26. for (k=1;k<=n;k<<=1)
  27. {
  28. F(i,0,n-1) {j=sa[i]-k;if(j<0)j+=n;tmp[cnt[rk[j]]++]=j;}
  29. sa[tmp[cnt[0]=0]]=j=0;
  30. F(i,1,n-1)
  31. {
  32. if (rk[tmp[i]]!=rk[tmp[i-1]]||rk[tmp[i]+k]!=rk[tmp[i-1]+k]) cnt[++j]=i;
  33. sa[tmp[i]]=j;
  34. }
  35. memcpy(rk,sa,n*sizeof(int));memcpy(sa,tmp,n*sizeof(int));
  36. if (j>=n-1) break;
  37. }
  38. for (i=k=0;i<n;h[rk[i++]]=k)
  39. for (k?k--:0,j=sa[rk[i]-1];s[i+k]==s[j+k];k++);
  40. F(i,0,n-1) st[i][0]=h[i];
  41. F(i,1,20) F(j,0,n-(1<<i)) st[j][i]=min(st[j][i-1],st[j+(1<<(i-1))][i-1]);
  42. F(i,1,n-1) pre[i]=pre[i-1]+n-sa[i]-h[i]-1;
  43. Sum=pre[n-1];
  44. }
  45. int query(int l,int r)
  46. {
  47. int t=_log2[r-l+1];
  48. return min(st[l][t],st[r-(1<<t)+1][t]);
  49. }
  50. ll lcp(int a,int b)
  51. {
  52. if (a==b) return inf;
  53. int aa=rk[a],bb=rk[b];
  54. return query(min(aa,bb)+1,max(aa,bb));
  55. }
  56. void find(ll x,int n,int &l,int &r)
  57. {
  58. int le=1,ri=n;
  59. while (le<ri)
  60. {
  61. int mid=le+ri>>1;
  62. if (pre[mid]>=x) ri=mid;
  63. else le=mid+1;
  64. }
  65. int tmp=x-pre[le-1]+h[le];
  66. l=sa[le];r=l+tmp-1;
  67. }
  68. }SA,SB;
  69.  
  70. int n,q;
  71. char s[maxn];
  72.  
  73. int main()
  74. {
  75. F(i,2,maxn-1) _log2[i]=_log2[i>>1]+1;
  76. scanf("%d%d",&n,&q);
  77. scanf("%s",s);
  78. F(i,0,n-1)
  79. {
  80. SA.s[i]=s[i]-'a'+1;
  81. SB.s[n-i-1]=s[i]-'a'+1;
  82. }
  83. SA.s[n]=0; SB.s[n]=0;
  84. SA.build(n,30); SB.build(n,30);
  85. F(i,1,q)
  86. {
  87. ll x,y;
  88. int xl,xr,yl,yr;
  89. scanf("%lld%lld",&x,&y);
  90. if (x>SA.Sum||y>SA.Sum) {printf("-1\n");continue;}
  91. SA.find(x,n,xl,xr); SA.find(y,n,yl,yr);
  92. ll lcp=SA.lcp(xl,yl),rcp=SB.lcp(n-yr-1,n-xr-1);
  93. int l=min(xr-xl+1,yr-yl+1); lcp=min(lcp,(ll)l); rcp=min(rcp,(ll)l);
  94. printf("%lld\n",lcp*lcp+rcp*rcp);
  95. }
  96. }

  

BZOJ 3230 相似子串 ——后缀数组的更多相关文章

  1. BZOJ 3230 相似子串 | 后缀数组 二分 ST表

    BZOJ 3230 相似子串 题面 题解 首先我们要知道询问的两个子串的位置. 先正常跑一遍后缀数组并求出height数组. 对于每一个后缀suffix(i),考虑以i开头的子串有多少是之前没有出现过 ...

  2. bzoj 3230 相似子串——后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 作出后缀数组,从 LCP 看每个位置对于本质不同子串的贡献,而且他们已经按前面部分排好 ...

  3. BZOJ 3230: 相似子串(后缀数组)

    传送门 解题思路 其实题目挺好想的.首先子串排名可以由后缀数组求得,因为不算重复的,所以后缀数组的每个后缀排名的去掉\(lcp\)的前缀排名为当前后缀的子串排名.这样就可以预处理出每个后缀的\(l,r ...

  4. bzoj 3230 相似子串 —— 后缀数组+二分

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3230 先算出每个后缀贡献子串的区间: 然后前缀LCP直接查询,后缀LCP二分长度,查询即可: ...

  5. BZOJ 1396: 识别子串( 后缀数组 + 线段树 )

    这道题各位大神好像都是用后缀自动机做的?.....蒟蒻就秀秀智商写一写后缀数组解法..... 求出Height数组后, 我们枚举每一位当做子串的开头. 如上图(x, y是height值), Heigh ...

  6. poj 2774 最长公共子串 后缀数组

    Long Long Message Time Limit: 4000MS   Memory Limit: 131072K Total Submissions: 25752   Accepted: 10 ...

  7. URAL 1297 最长回文子串(后缀数组)

    1297. Palindrome Time limit: 1.0 secondMemory limit: 64 MB The “U.S. Robots” HQ has just received a ...

  8. poj 1743 Musical Theme(最长重复子串 后缀数组)

    poj 1743 Musical Theme(最长重复子串 后缀数组) 有N(1 <= N <=20000)个音符的序列来表示一首乐曲,每个音符都是1..88范围内的整数,现在要找一个重复 ...

  9. BZOJ 3230: 相似子串( RMQ + 后缀数组 + 二分 )

    二分查找求出k大串, 然后正反做后缀数组, RMQ求LCP, 时间复杂度O(NlogN+logN) -------------------------------------------------- ...

随机推荐

  1. Azure 项目构建 – 部署 Jenkins 服务器以实现持续集成(CI)

    通过完整流程详细介绍了如何通过 Azure 虚拟机.虚拟网络等服务在 Azure 平台上快速搭建 Jenkins 服务器. 此系列的全部课程 https://school.azure.cn/curri ...

  2. selenium-Python之定位下拉框选择

    1.通过select 进行定位下拉框 下拉框如图所示 通过代码定位 #通过index进行选择Select(driver.find_element_by_id("cardType") ...

  3. Spring 配置定时器(注解+xml)方式—整理

    一.注解方式 1. 在Spring的配置文件ApplicationContext.xml,首先添加命名空间 xmlns:task="http://www.springframework.or ...

  4. windows8无脑式双系统安装教程(转)

    转:http://blog.csdn.net/poem_qianmo/article/details/7334987 首先去微软官网将ISO文件下载下来,分为32bit跟64bit两个版本,因人而异, ...

  5. URAL 2048 Histroy(打表+模拟)

    因为年历是400年一个循环节的,所以递推出一年的情况,然后递推处理出一个循环节的情况.对于询问,求一个类似前缀和的东西就好了. 跑出来和比样例小一,把A和B加一以后交后AC... 写得时候注意变量的定 ...

  6. 转向ARC的说明

    转自hherima的博客原文:Transitioning to ARC Release Notes(苹果官方文档) ARC是一个编译器特征,它提供了对OC对象自动管理内存.ARC让开发者专注于感兴趣的 ...

  7. struts2的动态方法配置

    动态方法调用配置 <package name="test" extends="struts-default"> <aciton name=&q ...

  8. c++ 结构体,设置物品体积并输出物品属性

    #include <iostream> using namespace std; struct box { char maker[40]; float height; float widt ...

  9. GIMP里的Path移动,旋转,翻转操作

    1/Path的移动: 快捷键Ctrl+Move Tool 2/Path的旋转: 选择Rotate Tool,在Path中选择,出现十字圈. Angel下的滑块调节一定的角度,在合适的位置即可. 3/P ...

  10. python基础知识13-迭代器与生成器,导入模块

    异常处理作业讲解 file = open('/home/pyvip/aaa.txt','w+') try: my_dict = {'name':'adb'} file.write(my_dict['a ...