https://www.lydsy.com/JudgeOnline/problem.php?id=4650

https://www.luogu.org/problemnew/show/P1117

如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的。

例如,对于字符串 aabaabaa,如果令 A=aab,B=a,我们就找到了这个字符串拆分成 AABB的一种方式。

一个字符串可能没有优秀的拆分,也可能存在不止一种优秀的拆分。比如我们令 A=a,B=baa,也可以用 AABB表示出上述字符串;但是,字符串 abaabaa 就没有优秀的拆分。

现在给出一个长度为 n的字符串 S,我们需要求出,在它所有子串的所有拆分方式中,优秀拆分的总个数。这里的子串是指字符串中连续的一段。

以下事项需要注意:

1.出现在不同位置的相同子串,我们认为是不同的子串,它们的优秀拆分均会被记入答案。

2.在一个拆分中,允许出现 A=B。例如 cccc 存在拆分 A=B=c。

3.字符串本身也是它的一个子串。

这类题的方法还是见少了啊,听说神犇都是一眼秒的,果然还是有很大的差距啊,唉……

对于AABB,我们完全可以只考虑AA,这样令f[i]表示以i结尾的AA数量,g[i]表示以i开头的AA数量,那么显然就是sigma(f[i]g[i+1])。

对于AA怎么求,大体的思路和URAL1297:Palindrome求回文串是一样的,就是通过比较后缀的公共前缀来得到AA的长度,进而求出这段区间内f[i]g[i]的值。

但是这样显然是O(n^2)的。

我们用(黑)分(科)块(技)的思想,枚举l,将字符串分成l大小的块,则长度为l的AA一定最少跨过两个块,于是对于块边界点,求一次公共前缀和后缀,拼在一起就是我们所要的答案,复杂度调和级数O(nlogn)。

注意,为了让复杂度正确,我们对区间的f和g差分。

  1. #include<cstdio>
  2. #include<cmath>
  3. #include<iostream>
  4. #include<vector>
  5. #include<cstring>
  6. #include<algorithm>
  7. #include<cctype>
  8. using namespace std;
  9. typedef long long ll;
  10. const int N=2e6+;
  11. char s[N];
  12. int n,m,rk[N],height[N],sa[N],w[N],cas,dp[N][],lg[N];
  13. int f[N],g[N];
  14. inline int qpow(int a){return <<a;}
  15. inline bool pan(int *x,int i,int j,int k){
  16. int ti=i+k<n?x[i+k]:-;
  17. int tj=j+k<n?x[j+k]:-;
  18. return ti==tj&&x[i]==x[j];
  19. }
  20. void SA_init(){
  21. int *x=rk,*y=height,r=;
  22. for(int i=;i<r;i++)w[i]=;
  23. for(int i=;i<n;i++)w[s[i]]++;
  24. for(int i=;i<r;i++)w[i]+=w[i-];
  25. for(int i=n-;i>=;i--)sa[--w[s[i]]]=i;
  26. r=;x[sa[]]=;
  27. for(int i=;i<n;i++)
  28. x[sa[i]]=s[sa[i]]==s[sa[i-]]?r-:r++;
  29. for(int k=;r<n;k<<=){
  30. int yn=;
  31. for(int i=n-k;i<n;i++)y[yn++]=i;
  32. for(int i=;i<n;i++)
  33. if(sa[i]>=k)y[yn++]=sa[i]-k;
  34. for(int i=;i<r;i++)w[i]=;
  35. for(int i=;i<n;i++)w[x[y[i]]]++;
  36. for(int i=;i<r;i++)w[i]+=w[i-];
  37. for(int i=n-;i>=;i--)sa[--w[x[y[i]]]]=y[i];
  38. swap(x,y);r=;x[sa[]]=;
  39. for(int i=;i<n;i++)
  40. x[sa[i]]=pan(y,sa[i],sa[i-],k)?r-:r++;
  41. }
  42. }
  43. inline void height_init(){
  44. int i,j,k=;
  45. for(int i=;i<=n;i++)rk[sa[i]]=i;
  46. for(int i=;i<n;i++){
  47. if(k)k--;
  48. j=sa[rk[i]-];
  49. while(s[i+k]==s[j+k])k++;
  50. height[rk[i]]=k;
  51. }
  52. }
  53. void st_init(){
  54. for(int i=;i<=n;i++){
  55. dp[i-][]=height[i];
  56. lg[i]=lg[i-];
  57. if((<<lg[i]+)==i)lg[i]++;
  58. }
  59. for(int j=;j<=lg[n];j++){
  60. for(int i=;i<n;i++){
  61. if(i+qpow(j)->=n)break;
  62. dp[i][j]=min(dp[i][j-],dp[i+qpow(j-)][j-]);
  63. }
  64. }
  65. }
  66. int lcp(int a,int b){
  67. int l=rk[a],r=rk[b];
  68. if(r<l)swap(l,r);
  69. l--;r--;
  70. if(r<)return ;
  71. l++;
  72. int len=r-l+;
  73. int k=lg[len];
  74. int h=qpow(k);
  75. return min(dp[l][k],dp[r-h+][k]);
  76. }
  77. int main(){
  78. scanf("%d",&cas);
  79. while(cas--){
  80. memset(f,,sizeof(f));
  81. memset(g,,sizeof(g));
  82. cin>>s;
  83. m=strlen(s),n=*m+;
  84. s[m]='$';
  85. for(int i=m+;i<n;i++){
  86. s[i]=s[n-i-];
  87. }
  88. s[n++]=;
  89. SA_init();
  90. n--;
  91. height_init();
  92. st_init();
  93. for(int l=;l<=m/;l++){
  94. for(int i=,j=l;j<m;i+=l,j+=l){
  95. int p=min(l,lcp(i,j));
  96. int s=min(l,lcp(n-i-,n-j-));
  97. if(p+s->=l){
  98. f[j-s+l]++;f[j+p]--;
  99. g[i-s+]++;g[i+p-l+]--;
  100. }
  101. }
  102. }
  103. ll ans=;
  104. for(int i=;i<m;i++){
  105. f[i]+=f[i-];
  106. g[i]+=g[i-];
  107. }
  108. for(int i=;i<m-;i++){
  109. ans+=(ll)f[i]*g[i+];
  110. }
  111. printf("%lld\n",ans);
  112. }
  113. return ;
  114. }

+++++++++++++++++++++++++++++++++++++++++++

+本文作者:luyouqi233。               +

+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

BZOJ4650:[NOI2016]优秀的拆分——题解的更多相关文章

  1. [UOJ#219][BZOJ4650][Noi2016]优秀的拆分

    [UOJ#219][BZOJ4650][Noi2016]优秀的拆分 试题描述 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 A 和 B 是任意非空字符串,则我们称该字符串的这种拆分是优秀 ...

  2. BZOJ4650 [NOI2016]优秀的拆分 【后缀数组】

    题目 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串,则我们称该字符串的这种拆 分是优秀的.例如,对于字符串 aabaabaa,如果令 A=aabA=aa ...

  3. 题解【bzoj4650 [NOI2016]优秀的拆分】

    Description 求对每一个连续字串将它切割成形如 AABB 的形式的方案数之和 Solution 显然 AABB 是由两个 AA 串拼起来的 考虑维护两个数组 a[i] 和 b[i] ,其中 ...

  4. UOJ#219/BZOJ4650 [NOI2016]优秀的拆分 字符串 SA ST表

    原文链接http://www.cnblogs.com/zhouzhendong/p/9025092.html 题目传送门 - UOJ#219 (推荐,题面清晰) 题目传送门 - BZOJ4650 题意 ...

  5. BZOJ4650 NOI2016优秀的拆分(后缀数组)

    显然只要求出以每个位置开始的AA串数量就可以了,将其和反串同位置的结果乘一下,加起来就是答案.考虑对每种长度的字符串计数.若当前考虑的A串长度为x,我们每隔x个字符设一个关键点,求出相邻两关键点的后缀 ...

  6. [BZOJ4650][NOI2016]优秀的拆分(SAM构建SA)

    关于解法这个讲的很清楚了,主要用了设关键点的巧妙思想. 主要想说的是一个刚学的方法:通过后缀自动机建立后缀树,再转成后缀数组. 后缀数组功能强大,但是最令人头疼的地方是模板太难背容易写错.用这个方法, ...

  7. BZOJ4650: [Noi2016]优秀的拆分

    考场上没秒的话多拿5分并不划算的样子. 思想其实很简单嘛. 要统计答案,求以每个位置开始和结束的AA串数量就好了.那么枚举AA中A的长度L,每L个字符设一个关键点,这样AA一定经过相邻的两个关键点.计 ...

  8. bzoj千题计划317:bzoj4650: [Noi2016]优秀的拆分(后缀数组+差分)

    https://www.lydsy.com/JudgeOnline/problem.php?id=4650 如果能够预处理出 suf[i] 以i结尾的形式为AA的子串个数 pre[i] 以i开头的形式 ...

  9. BZOJ4650: [Noi2016]优秀的拆分(hash 调和级数)

    题意 题目链接 Sol NOI的题都这么良心么.. 先交个\(n^4\)暴力 => 75 hash优化一下 => 90 然后\(90\)到\(100\)分之间至少差了\(10\)难度台阶= ...

随机推荐

  1. xencenter迁移云主机方法

    问题:POOL中计算节点内存不足. 解决方法:1.为计算节点添加内存(费用高)2.将部分资源迁移到其它POOL中. 方法: 1.选择要迁移的虚拟机 2.选择保存路径 这里可以看到可以批量导出: 注意: ...

  2. JDK1.8改为JDK1.7过程

    电脑之前eclipse版本要求JDK1.8版本,现在要用jboss7.1做性能测试,目前仅支持JDK7.故需要降级. 网上有很多说把1.8删掉,这种做法我是不建议的,那么要用的时候呢?又得装回来多蛋疼 ...

  3. Jmeter做压力测试的心得

    什么是性能压测? 也是最近刚刚接触到,就是被测试的系统,在一定的访问压力下,看程序运行是否稳定/服务器运行是否稳定,通常情况,是模拟多个请求同时 请求服务器,也就是在某个时间内,比如说1秒内,调用接口 ...

  4. [Clr via C#读书笔记]Cp5基元类型引用类型值类型

    Cp5基元类型引用类型值类型 基元类型 编译器直接支持的类型,基元类型直接映射到FCL中存在的类型. 作者希望使用FCL类型名称而避免使用关键字.他的理由是为了更加的清晰的知道自己写的类型是哪种.但是 ...

  5. ARM架构中的程序执行与调用

    ARM架构中的程序执行与调用 1. 几个名词 ABI : 可执行文件必须遵守的规范,以在特定执行环境中运行: 单独产生的可重定址的文件必须遵守的规范,以用来链接和执行. EABI: 适用于嵌入式环境的 ...

  6. 有关WCSF的几点整理

    本文示例代码 一.CreateNew Attribute实现属性注入 Steps: 1/ aspx创建某个服务的属性. 2/ 为其添加[CreateNew] Attribute. 3/ 页面继承自Mi ...

  7. 关于docker 基础使用记录

    Docker Hub地址:https://hub.docker.com Docker Hub 存放着 Docker 及其组件的所有资源.Docker Hub 可以帮助你与同事之间协作,并获得功能完整的 ...

  8. Discover the Web(栈模拟)

    Description Standard web browsers contain features to move backward and forward among the pages rece ...

  9. HBase 参考文档翻译之 Getting Started

    本篇是对HBase官方参考文档的大体翻译,介于本人英文水平实在有限,难免有纰漏之处.本篇不只是对官方文档的翻译,还加入了一些本人对HBase的理解.在翻译过程中,一些没有营养的废话,我就忽略了没有翻译 ...

  10. 算法与数据结构实验题 4.2 小 F 打怪

    ★实验任务 小 F 很爱打怪,今天因为系统 bug,他提前得知了 n 只怪的出现顺序以及击 倒每只怪得到的成就值 ai.设第一只怪出现的时间为第 1 秒,这个游戏每过 1 秒 钟出现一只新怪且没被击倒 ...