[LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分

题意

给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案

\(|S|\le 30000\) (\(95\%\) 数据 \(|S|\le 2000\))

题解

考场上遇见这题直接打95分暴力哈希跑路就完事了吧

\(O(n^2)\) 暴力就直接枚举所有子串看它是不是 AA 型的, 在左右端点处分别标记一下, 然后枚举断点把两边的方案数乘起来就完事了.

考虑优化这个暴力. 我们枚举这个 AA 串中 A 的长度 \(l\), 然后每隔 \(l\) 取一个关键点, 那么每个 AA 串必然会覆盖两个关键点. 对于每对相邻的关键点 \(a\) 和 \(b\), 我们计算 \(p=\operatorname{LCP}(S[a:],S[b:])\) 以及 \(s=\operatorname{LCS}(S[:a-1],S[:b-1])\) . 那么只要 \(p+s\ge l\) 就会有 AA 串出现. 画画图可以发现 \([a-s,a-(l-p)]\) 都可以是 AA 串的左端点. 直接在差分数组上修改左右端点就可以了. 注意只能计算同时包含这两个相邻的关键点的 AA 串, 所以应该和 \([a-l+1,a]\) 取交集. 算完之后前缀和一下按照 \(O(n^2)\) 暴力里的操作算最终答案就可以了.

参考代码

  1. #include <bits/stdc++.h>
  2. const int MAXN=1e5+10;
  3. typedef long long intEx;
  4. struct SuffixArray{
  5. char s[MAXN];
  6. int SA[MAXN];
  7. int rank[MAXN];
  8. int stmin[20][MAXN];
  9. int* height=stmin[0];
  10. void Build();
  11. int LCP(int,int);
  12. };
  13. SuffixArray pf,sf;
  14. int n;
  15. int lg[MAXN];
  16. int cnt[MAXN];
  17. char buf[MAXN];
  18. int lcnt[MAXN];
  19. int rcnt[MAXN];
  20. int* x=new int[MAXN];
  21. int* y=new int[MAXN];
  22. int LCP(int,int);
  23. int LCS(int,int);
  24. int main(){
  25. int T;
  26. scanf("%d",&T);
  27. for(int i=2;i<MAXN;i++)
  28. lg[i]=lg[i>>1]+1;
  29. while(T--){
  30. scanf("%s",buf+1);
  31. n=strlen(buf+1);
  32. for(int i=1;i<=n;i++)
  33. pf.s[i]=sf.s[n-i+1]=buf[i];
  34. pf.Build();
  35. sf.Build();
  36. memset(lcnt,0,sizeof(int)*(n+1));
  37. memset(rcnt,0,sizeof(int)*(n+1));
  38. for(int len=1;(len<<1)<=n;len++){
  39. for(int a=1,b;(b=a+len)<=n;a=b){
  40. int p=LCP(a,b);
  41. int s=LCS(a-1,b-1);
  42. if(p+s>=len){
  43. int l=std::max(a-len+1,a-s);
  44. int r=std::min(a-(len-p),a);
  45. ++lcnt[l];
  46. --lcnt[r+1];
  47. ++rcnt[l+(len<<1)-1];
  48. --rcnt[r+(len<<1)];
  49. }
  50. }
  51. }
  52. for(int i=1;i<=n;i++){
  53. lcnt[i]+=lcnt[i-1];
  54. rcnt[i]+=rcnt[i-1];
  55. }
  56. intEx ans=0;
  57. for(int i=1;i<n;i++)
  58. ans+=1ll*rcnt[i]*lcnt[i+1];
  59. printf("%lld\n",ans);
  60. }
  61. return 0;
  62. }
  63. int LCP(int a,int b){
  64. return pf.LCP(a,b);
  65. }
  66. int LCS(int a,int b){
  67. return sf.LCP(n-a+1,n-b+1);
  68. }
  69. int SuffixArray::LCP(int a,int b){
  70. if(a<1||a>n||b<1||b>n)
  71. return 0;
  72. else if(a==b)
  73. return n-a+1;
  74. else{
  75. a=rank[a];
  76. b=rank[b];
  77. if(a>b)
  78. std::swap(a,b);
  79. int p=lg[b-a];
  80. ++a;
  81. return std::min(stmin[p][a],stmin[p][b-(1<<p)+1]);
  82. }
  83. }
  84. void SuffixArray::Build(){
  85. int m=127;
  86. memset(x,0,sizeof(int)*(n+2));
  87. memset(y,0,sizeof(int)*(n+2));
  88. memset(cnt,0,sizeof(int)*(m+1));
  89. for(int i=1;i<=n;i++)
  90. ++cnt[x[i]=s[i]];
  91. for(int i=1;i<=m;i++)
  92. cnt[i]+=cnt[i-1];
  93. for(int i=n;i>=1;i--)
  94. SA[cnt[x[i]]--]=i;
  95. for(int k=1;k<n;k<<=1){
  96. int p=0;
  97. for(int i=n-k+1;i<=n;i++)
  98. y[++p]=i;
  99. for(int i=1;i<=n;i++)
  100. if(SA[i]>k)
  101. y[++p]=SA[i]-k;
  102. memset(cnt,0,sizeof(int)*(m+1));
  103. for(int i=1;i<=n;i++)
  104. ++cnt[x[i]];
  105. for(int i=1;i<=m;i++)
  106. cnt[i]+=cnt[i-1];
  107. for(int i=n;i>=1;i--)
  108. SA[cnt[x[y[i]]]--]=y[i];
  109. std::swap(x,y);
  110. x[SA[1]]=1;
  111. p=1;
  112. for(int i=2;i<=n;i++)
  113. x[SA[i]]=(y[SA[i]]==y[SA[i-1]]&&y[SA[i]+k]==y[SA[i-1]+k])?p:++p;
  114. if(p>=n)
  115. break;
  116. m=p;
  117. }
  118. for(int i=1;i<=n;i++)
  119. rank[SA[i]]=i;
  120. int k=0;
  121. for(int i=1;i<=n;i++){
  122. if(rank[i]==1)
  123. continue;
  124. if(k)
  125. --k;
  126. int j=SA[rank[i]-1];
  127. while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])
  128. ++k;
  129. height[rank[i]]=k;
  130. }
  131. for(int i=1;(1<<i)<=n;i++){
  132. for(int j=2;j<=n;j++){
  133. stmin[i][j]=stmin[i-1][j];
  134. if(j+(1<<(i-1))<=n)
  135. stmin[i][j]=std::min(stmin[i][j],stmin[i-1][j+(1<<(i-1))]);
  136. }
  137. }
  138. }

[LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分的更多相关文章

  1. [bzoj 4650][NOI 2016]优秀的拆分

    传送门 Description 如果一个字符串可以被拆分为\(AABB\) 的形式,其中$ A$和 \(B\)是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串\(aabaaba ...

  2. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  3. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

  4. [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程

    [LOJ 2718][UOJ 393][BZOJ 5415][NOI 2018]归程 题意 给定一张无向图, 每条边有一个距离和一个高度. 再给定 \(q\) 组可能在线的询问, 每组询问给定一个点 ...

  5. [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士

    [LOJ 2721][UOJ 396][BZOJ 5418][NOI 2018]屠龙勇士 题意 题面好啰嗦啊直接粘LOJ题面好了 小 D 最近在网上发现了一款小游戏.游戏的规则如下: 游戏的目标是按照 ...

  6. NOI 2016 优秀的拆分 (后缀数组+差分)

    题目大意:给你一个字符串,求所有子串的所有优秀拆分总和,优秀的拆分被定义为一个字符串可以被拆分成4个子串,形如$AABB$,其中$AA$相同,$BB$相同,$AB$也可以相同 作为一道国赛题,95分竟 ...

  7. 【BZOJ 4650】【UOJ #219】【NOI 2016】优秀的拆分

    http://www.lydsy.com/JudgeOnline/problem.php?id=4650 http://uoj.ac/problem/219 这里有非常好的题解qwq 接着道题复习一下 ...

  8. UOJ #219 BZOJ 4650 luogu P1117 [NOI2016]优秀的拆分 (后缀数组、ST表)

    连NOI Day1T1都不会做...看了题解都写不出来还要抄Claris的代码.. 题目链接: (luogu)https://www.luogu.org/problemnew/show/P1117 ( ...

  9. 字符串(后缀自动机):NOI 2016 优秀的拆分

    [问题描述] 如果一个字符串可以被拆分为 AABB 的形式,其中 A 和 B 是任意非空字符串, 则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aabaabaa,如果令 A = aab, B ...

随机推荐

  1. Note | 用Hugo搭建博客并部署到GitHub Pages

    目录 1. 本地搭建 1.1 安装Hugo 1.2 创建站点 1.3 新建页面和文章 1.4 使用主题 1.5 修改配置文件 1.6 预览 2. 部署 之前担心过现有博客平台(如博客园,CSDN)突然 ...

  2. es6入门7--Set Map数据结构

    本文作为ES6入门第十三章的学习整理笔记,可能会包含少部分个人的理解推测,若想阅读更详细的介绍,还请阅读原文ES6入门 一.set数据结构 1.set不接受重复值 ES6新增了Set构造函数用于创建s ...

  3. hyper-v简介及安装使用

     前言:作为IT界的巨头,微软自己的虚拟化技术,也是微软第一个采用Vmware与CitrixXen一样基于hypervisor的虚拟化技术,有着自己可圈可点的地方,微软自己的虚拟化技术嘛,对windo ...

  4. 雅礼集训2019 D7T2 Subsequence

    雅礼集训2019 D7T2 Subsequence 直接贴题解: 平衡树代码: #include<bits/stdc++.h> #define ll long long #define N ...

  5. Do Deep Nets Really Need to be Deep?

    url: https://arxiv.org/pdf/1312.6184.pdf year: NIPS2014 浅网络学习深网络的函数表示, 训练方法就是使用深网络的 logits(softmax i ...

  6. okhttp浅析

    转载自:http://www.ishenping.com/ArtInfo/69561.html 1.okhttp工作的大致流程 1.1.整体流程 (1).当我们通过OkhttpClient创建一个Ca ...

  7. python基础(12):函数(二)

    1. 函数参数 之前我们说过了传参,如果我们需要给⼀个函数传参,⽽参数⼜是不确定的,或者我给⼀个函数传很多参数,我的形参就要写很多,很⿇烦,怎么办呢,我们可以考虑使⽤动态参数. 形参的第三种: 动态参 ...

  8. python爬取网站视频保存到本地

    前言 文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,版权归原作者所有,如有问题请及时联系我们以作处理. 作者: Woo_home PS:如有需要Python学习资料的小伙伴可以加点 ...

  9. java核心技术第五篇之事务和MVC模式

    第一部分:事务1.事务的简介: 1.1 在一组操作中(比如增加操作,修改操作),只有增加和修改操作都成功之后,这两个操作才能真正的成功. ,如果这两个操作中,有一个失败了,这两个操作都失败了. 1.2 ...

  10. SpringBoot(一):构建第一个SpringBoot工程

    1.项目格式如下: 1.启动类: package com.monkey01.springbootstart; import org.springframework.boot.SpringApplica ...