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

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

枚举每一段 a 的长度,然后分块,后缀数组求出每一块首关键点附近的可行范围;

然后用线段树区间加,区间查询;

在开头范围查询结尾,就得到长度 <= 当前长度 d 的前半部分接上长度 = d 的后半部分的答案;

在结尾范围查询开头,就得到长度 = d 的前半部分接上长度 < d 的后半部分的答案,正好组合了所有情况!

于是写了,跑出来发现比别人慢了很多;

然后发现为什么要边找边算答案...可以差分数组区间加,最后直接每个位置算答案即可...

注意多组数据,要清空 rk[n+1] 和 tp[n+1],因为求后缀数组的时候用到了超出 n 的 tp(rk) 。

代码如下:

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define mid ((l+r)>>1)
  5. #define ls (x<<1)
  6. #define rs ((x<<1)|1)
  7. using namespace std;
  8. typedef long long ll;
  9. int const xn=6e4+;//n<<1
  10. int rk[xn],sa[xn],tax[xn],tp[xn],ht[xn][],bin[],bit[xn],op[xn];
  11. ll sum[][xn<<],lzy[][xn<<];//n<<2
  12. char s[xn];
  13. int Min(int x,int y){return x<y?x:y;}
  14. int Max(int x,int y){return x>y?x:y;}
  15. void rsort(int n,int m)
  16. {
  17. for(int i=;i<=m;i++)tax[i]=;
  18. for(int i=;i<=n;i++)tax[rk[tp[i]]]++;
  19. for(int i=;i<=m;i++)tax[i]+=tax[i-];
  20. for(int i=n;i;i--)sa[tax[rk[tp[i]]]--]=tp[i];
  21. }
  22. void work(int n)
  23. {
  24. int m=; for(int i=;i<=n;i++)rk[i]=s[i],tp[i]=i;
  25. rk[n+]=; tp[n+]=;//!
  26. rsort(n,m);
  27. for(int k=;k<=n;k<<=)
  28. {
  29. int num=;
  30. for(int i=n-k+;i<=n;i++)tp[++num]=i;
  31. for(int i=;i<=n;i++)
  32. if(sa[i]>k)tp[++num]=sa[i]-k;
  33. rsort(n,m); swap(rk,tp);
  34. rk[sa[]]=; num=;
  35. for(int i=;i<=n;i++)
  36. {
  37. int u=Min(n+,sa[i]+k),v=Min(n+,sa[i-]+k);//
  38. rk[sa[i]]=(tp[sa[i]]==tp[sa[i-]]&&tp[u]==tp[v])?num:++num;//tp[n+1]!
  39. }
  40. if(num==n)break;
  41. m=num;
  42. }
  43. }
  44. void geth(int n)
  45. {
  46. int k=; ht[][]=;
  47. for(int i=;i<=n;i++)
  48. {
  49. if(rk[i]==)continue;
  50. if(k)k--; int j=sa[rk[i]-];
  51. while(i+k<=n&&j+k<=n&&s[i+k]==s[j+k])k++;
  52. ht[rk[i]][]=k;
  53. }
  54. for(int i=;i<;i++)
  55. for(int j=;j+bin[i]-<=n;j++)
  56. ht[j][i]=Min(ht[j][i-],ht[j+bin[i-]][i-]);
  57. }
  58. int getlcp(int x,int y,int n)
  59. {
  60. if(x==y)return n-x+;
  61. x=rk[x]; y=rk[y];
  62. if(x>y)swap(x,y); x++;
  63. int r=bit[y-x+];
  64. return Min(ht[x][r],ht[y-bin[r]+][r]);
  65. }
  66. void psd(int t,int x,int l,int r)
  67. {
  68. if(!lzy[t][x])return;
  69. int d=lzy[t][x]; lzy[t][x]=;
  70. sum[t][ls]+=d*(mid-l+); lzy[t][ls]+=d;
  71. sum[t][rs]+=d*(r-mid); lzy[t][rs]+=d;
  72. }
  73. void update(int t,int x,int l,int r,int L,int R)
  74. {
  75. if(L>R)return;
  76. if(l>=L&&r<=R){sum[t][x]+=r-l+; lzy[t][x]++; return;}
  77. psd(t,x,l,r);
  78. if(mid>=L)update(t,ls,l,mid,L,R);
  79. if(mid<R)update(t,rs,mid+,r,L,R);
  80. sum[t][x]=sum[t][ls]+sum[t][rs];
  81. }
  82. ll query(int t,int x,int l,int r,int L,int R)
  83. {
  84. if(L>R)return ;
  85. if(l>=L&&r<=R)return sum[t][x];
  86. psd(t,x,l,r); ll ret=;
  87. if(mid>=L)ret+=query(t,ls,l,mid,L,R);
  88. if(mid<R)ret+=query(t,rs,mid+,r,L,R);
  89. return ret;
  90. }
  91. int main()
  92. {
  93. int T; scanf("%d",&T);
  94. bin[]=; for(int i=;i<;i++)bin[i]=(bin[i-]<<);
  95. bit[]=; for(int i=;i<=6e4;i++)bit[i]=bit[i>>]+;//6e4
  96. while(T--)
  97. {
  98. memset(sum,,sizeof sum);
  99. memset(lzy,,sizeof lzy);
  100. scanf("%s",s+); int n=strlen(s+);
  101. s[n+]='a'-;
  102. for(int i=n+,k=n;k;i++,k--)s[i]=s[k],op[k]=i;
  103. work(n*+); geth(n*+); ll ans=;
  104. for(int d=;d<=n;d++)
  105. for(int i=;i+d<=n;i+=d)
  106. {
  107. int j=i+d;
  108. int t2=Min(d,getlcp(i,j,n));
  109. int t1=Min(d,getlcp(op[i],op[j],n));
  110. if(t1+t2-<d)continue;
  111. int l=i-t1+,r=i+t2-d;//hd
  112. ans+=query(,,,n,Max(,l-),r-);//qtl
  113. ans+=query(,,,n,l+*d,Min(n,r+*d));//qhd
  114. update(,,,n,l,r); update(,,,n,l+*d-,r+*d-);
  115. }
  116. printf("%lld\n",ans);
  117. }
  118. return ;
  119. }

bzoj 4650 & 洛谷 P1117 优秀的拆分 —— 枚举关键点+后缀数组的更多相关文章

  1. 洛谷P1117 优秀的拆分【Hash】【字符串】【二分】【好难不会】

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

  2. 洛谷P1117 优秀的拆分

    题意:求一个字符串中有多少形如AABB的子串. 解:嗯...我首先极度SB的想了一个后缀自动机套线段树启发式合并的做法,想必会TLE. 然后跑去看题解,发现实在是妙不可言... 显然要对每个位置求出向 ...

  3. bzoj 4650(洛谷 1117) [Noi2016]优秀的拆分——枚举长度的关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4650 https://www.luogu.org/problemnew/show/P1117 ...

  4. 【洛谷 P4051】 [JSOI2007]字符加密(后缀数组)

    题目链接 两眼题.. 第一眼裸SA 第二眼要复制一倍再跑SA. 一遍过.. #include <cstdio> #include <cstring> #include < ...

  5. bzoj 2119 股市的预测 —— 枚举关键点+后缀数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2119 思路就是对于这个形如 ABA 的串,枚举 A 的长度,并按照长度分出几块,找到一些关键 ...

  6. 洛谷 P2404 自然数的拆分问题

    题目链接 https://www.luogu.org/problemnew/show/P2404 题目背景 木有...... 题目描述 任何一个大于1的自然数n,总可以拆分成若干个小于n的自然数之和. ...

  7. [BZOJ 3039&洛谷P4147]玉蟾宫 题解(单调栈)

    [BZOJ 3039&洛谷P4147]玉蟾宫 Description 有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地. ...

  8. bzoj 4816: 洛谷 P3704: [SDOI2017]数字表格

    洛谷很早以前就写过了,今天交到bzoj发现TLE了. 检查了一下发现自己复杂度是错的. 题目传送门:洛谷P3704. 题意简述: 求 \(\prod_{i=1}^{N}\prod_{j=1}^{M}F ...

  9. bzoj 1014: 洛谷 P4036: [JSOI2008]火星人

    题目传送门:洛谷P4036. 题意简述: 有一个字符串,支持插入字符,修改字符. 每次需要查询两个后缀的LCP长度. 最终字符串长度\(\le 100,\!000\),修改和询问的总个数\(\le 1 ...

随机推荐

  1. session的活化与钝化 (转)

    session的活化与钝化就是当用户访问时网站异常,不能丢掉session,所有也必须采用文件存储:和之前那个统计网站访问量一样的原理. class Person implements必须实现这两个接 ...

  2. HDU 1238 Substing

    思路: 1.找出n个字符串中最短的字符串Str[N] 2.从长到短找Str[N]的子子串 subStr[N],以及subStr[N]的反转字符串strrev(subStr[N]):(从长到短是做剪枝处 ...

  3. Nginx的长链接

    网站使用程序discuz3访问都正常,只有用户登录存在异常,具体就是:用户登陆后会马上显示未登录,然后刷新一下又变成了登录中 这个问题的原因显然是由于session导致,后台有多个web机器,当用户登 ...

  4. scons的使用

    以下测试是在linux下. 1.安装. $sudo apt install scons 2.查看安装版本: $scons --version 会出现以下内容: SCons by Steven Knig ...

  5. mysql中的左连接右连接内连接

    一. 初始化SQL语句 /*join 建表语句*/ drop database if exists test; create database test; use test; /* 左表t1*/ dr ...

  6. poj3683 2 -sat输出路径

    tarjan缩点,拓扑排序染色输出(貌似挑战上面没有拓扑啊,而且这样写还过了= =) 主要是找s,t,d,三者之间的关系,找出合取范式这题就很容易了 #include<map> #incl ...

  7. idea的常用设置

    1.官网 官网:http://www.jetbrains.com/idea/download/#section=windows 官方文档:http://www.jetbrains.com/help/i ...

  8. poi自定义颜色设置(转)

    原文链接  http://javapolo.iteye.com/blog/1604501 最近在项目的开发中使用到了apache poi,该组件可以让我们方便的操作excell,该工具非常容易上手,但 ...

  9. 进程(并发,并行) join start 进程池 (同步异步)

    一.背景知识 顾名思义,进程即正在执行的一个过程.进程是对正在运行程序的一个抽象.进程的概念起源于操作系统,是操作系统最核心的概念,也是操作系统提供的最古老也是最重要的抽象概念之一.操作系统的其他所有 ...

  10. (四)js数组方法一

    ES5数组方法: Array.prototype.filter()   对数组元素进行过滤 三个参数:元素值,下标,原数组 返回:过滤后符合条件的数组,不会改变原数组 let arr = [2,4,6 ...