传送门

Description

如果一个字符串可以被拆分为\(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. 字符串本身也是它的一个子串。

Solution

\(st[i]\)表示以\(i\)开始的有多少个形式如\(aa\)的子串

\(en[i]\)表示以\(j\)结束的有多少个形式如\(aa\)的字串

那么答案就是\(\sum_{i=1}^{n-1} en[i]*st[i+1]\)

怎么求这个东西呢?只考虑\(st\),因为把原字符串倒个序就能求\(en\)了

枚举\(aa\)中\(a\)的长度,然后每次我们只考虑\([ka+1,(k+1)a]\)这个区间上有多少个可以作为起始点的,它一定包含\((k+1)a\)这个位置,而后面与它相同的字串一定包括\((k+2)a\)这个位置,所以直接查询\(LCP((k+1)a,(k+2)a)\),以及\(LCS((k+1)a,(k+2)a)\),就可以啦。

根据调和级数和\(SA\),总复杂度是\(O(n\log n)\)

Code 

  1. #include<bits/stdc++.h>
  2. #define ll long long
  3. #define max(a,b) ((a)>(b)?(a):(b))
  4. #define min(a,b) ((a)<(b)?(a):(b))
  5. inline int read()
  6. {
  7. int x=0,f=1;char ch=getchar();
  8. while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
  9. while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
  10. return x*f;
  11. }
  12. #define MN 30005
  13. #define M(a) memset(a,0,sizeof a);
  14. char s[MN];
  15. int lg[MN],en[MN],st[MN],n;
  16. void init(){n=strlen(s+1);M(st);M(en);}
  17. class SA
  18. {
  19. private:
  20. int height[MN][19],p,q,sa[2][MN],rk[2][MN],num[MN];
  21. public:
  22. SA(){M(height);M(sa);M(rk);M(num);}
  23. inline void init(){M(height);M(sa);M(rk);M(num);}
  24. inline void build_sa()
  25. {
  26. register int i,j,k,mx;
  27. for(i=1;i<=n;++i) num[s[i]-'a'+1]++;
  28. for(i=1;i<=26;++i) num[i]+=num[i-1];
  29. for(i=1;i<=n;++i) sa[1][num[s[i]-'a'+1]--]=i;
  30. for(i=1;i<=n;++i) rk[1][sa[1][i]]=rk[1][sa[1][i-1]]+(s[sa[1][i-1]]!=s[sa[1][i]]);
  31. mx=rk[1][sa[1][n]];
  32. for(p=1,q=0,k=1;k<=n;k<<=1,p^=1,q^=1)
  33. {
  34. if(mx==n) break;
  35. for(i=1;i<=n;++i) num[rk[p][sa[p][i]]]=i;
  36. for(i=n;i;--i) if(sa[p][i]>k) sa[q][num[rk[p][sa[p][i]-k]]--]=sa[p][i]-k;
  37. for(i=n-k+1;i<=n;++i) sa[q][num[rk[p][i]]--]=i;
  38. for(i=1;i<=n;++i)
  39. rk[q][sa[q][i]]=rk[q][sa[q][i-1]]+(rk[p][sa[q][i]]!=rk[p][sa[q][i-1]]||rk[p][sa[q][i]+k]!=rk[p][sa[q][i-1]+k]);
  40. mx=rk[q][sa[q][n]];
  41. }
  42. for(i=k=1;i<=n;++i)
  43. {
  44. if(rk[p][i]==1) continue;if(k) k--;
  45. for(j=sa[p][rk[p][i]-1];j+k<=n&&i+k<=n&&s[i+k]==s[j+k];++k);
  46. height[rk[p][i]][0]=k;
  47. }
  48. for(i=1;i<=18;++i)for(j=n;j>=1&&j>(1<<i);--j)
  49. height[j][i]=min(height[j][i-1],height[j-(1<<i-1)][i-1]);
  50. }
  51. inline int LCP(int x,int y)
  52. {
  53. x=rk[p][x];y=rk[p][y];
  54. if(x>y) std::swap(x,y);
  55. return min(height[y][lg[y-x]],height[x+(1<<lg[y-x])][lg[y-x]]);
  56. }
  57. }A,revA;
  58. int main()
  59. {
  60. register int T,i,j;
  61. for(i=2;i<MN;++i) lg[i]=lg[i>>1]+1;
  62. T=read();printf("%d\n",T);
  63. while(T--)
  64. {
  65. memset(s,0,sizeof s);
  66. scanf("%s",s+1);
  67. init();
  68. A.init();A.build_sa();
  69. for(i=1;i+i<=n;++i) std::swap(s[i],s[n-i+1]);
  70. revA.init();revA.build_sa();
  71. register int len,x,y;
  72. for(len=1;len<=n;++len)for(i=len,j=len<<1;j<=n;i+=len,j+=len)
  73. {
  74. x=min(A.LCP(i,j),len);y=min(revA.LCP(n-i+1,n-j+1),len);
  75. if(x+y-1<len) continue;
  76. st[i-y+1]++;st[i+x-len+1]--;
  77. en[j+len-y]++;en[j+x]--;
  78. }
  79. for(i=1;i<=n;++i) st[i]+=st[i-1],en[i]+=en[i-1];
  80. register ll ans=0;
  81. for(i=1;i<n;++i) ans+=1ll*en[i]*st[i+1];
  82. printf("%lld\n",ans);
  83. }
  84. return 0;
  85. }

Blog来自PaperCloud,未经允许,请勿转载,TKS!

[bzoj 4650][NOI 2016]优秀的拆分的更多相关文章

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

    [LOJ 2083][UOJ 219][BZOJ 4650][NOI 2016]优秀的拆分 题意 给定一个字符串 \(S\), 求有多少种将 \(S\) 的子串拆分为形如 AABB 的拆分方案 \(| ...

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

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

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

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

  4. [NOI 2016]优秀的拆分

    Description 题库链接 给你一个长度为 \(n\) 的只含小写字母的字符串 \(S\) ,计算其子串有多少优秀的拆分. 如果一个字符串能被表示成 \(AABB\) 的形式,其中 \(A,B\ ...

  5. 解题:NOI 2016 优秀的拆分

    题面 其实题目不算很难,但是我调试的时候被玄学了,for循环里不写空格会RE,写了才能过.神**调了一个多小时是这么个不知道是什么的玩意(真事,可以问i207M=.=),心态爆炸 发现我们只要找AA或 ...

  6. [BZOJ]4650 优秀的拆分(Noi2016)

    比较有意思的一道后缀数组题.(小C最近是和后缀数组淦上了?) 放在NOI的考场上.O(n^3)暴力80分,O(n^2)暴力95分…… 即使想把它作为一道签到题也不要这么随便啊摔(╯‵□′)╯︵┻━┻ ...

  7. [BZOJ]4650: [Noi2016]优秀的拆分

    Time Limit: 30 Sec  Memory Limit: 512 MB Description 如果一个字符串可以被拆分为 AABBAABB 的形式,其中 AA 和 BB 是任意非空字符串, ...

  8. 【NOI 2016】优秀的拆分

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

  9. 【刷题】BZOJ 4650 [Noi2016]优秀的拆分

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

随机推荐

  1. vs项目模板创建和使用

    一.使用dotnet命令创建(适用于.NET Core,可以创建包含任意数量个项目的模板,但不会出现在vs的新建项目模板中) 官方文档:https://docs.microsoft.com/zh-cn ...

  2. 通过 Java 压缩文件,打包一个 tar.gz 采集器包

    一.如何通过 Java 打包文件 1.1 添加 Maven 依赖 <dependency> <groupId>org.apache.commons</groupId> ...

  3. 转载 AI-Talking 图算法

    https://mp.weixin.qq.com/s/2XRgJr-ydxHA3JxAZ_5HeA 图算法在风控业务的实践 直播行业中有很多业务风控问题,比如说批量注册.刷热度.垃圾信息以及薅羊毛等. ...

  4. 用BIO手写实现Redis客户端的探究(拒绝Jedis)

    在Redis的使用过程中,大多数人都是使用现成的客户端,如Jedis,Redisson,Lettuce.因此本文研究用BIO的方式手写Redis客户端尝试,对遇到的问题进行探究及总结. Redis通讯 ...

  5. 常见User-Agent大全

    window.navigator.userAgent 1) Chrome Win7: Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/535.1 (KH ...

  6. Flutter——消息框(Fluttertoast)

    引入依赖: dependencies: fluttertoast: ^3.1.3 import 'package:flutter/material.dart'; import 'package:flu ...

  7. vue 打印html

    1.https://github.com/xyl66/vuePlugs_printjs从这个路径下载print.js.放到你的代码中 2.我是放到我本地一个js文件中. 3.引入当前文件 //打印插件 ...

  8. 天兔 -Lepus 慢查询分析平台配置

    想要实现慢查询查询分析,需要在被监控端安装percona-toolkit工具.   1.被监控端安装软件包 yum -y install perl-IO-Socket-SSL yum -y insta ...

  9. [Abp vNext微服务实践] - 框架分析

    一.简介 abp vNext新框架的热度一直都很高,于是最近上手将vNext的微服务Demo做了一番研究.我的体验是,vNext的微服务架构确实比较成熟,但是十分难以上手,对于没有微服务开发经验的.n ...

  10. 基于ELK的日志分析、存储、展示

    原文:https://blog.51cto.com/11134648/2163789 ELK简介 ELK是一套完整的日志解决方案,由ElasticSearch.Logstash. Kibana这三款开 ...