【BZOJ4560】[NOI2016]优秀的拆分

题面

bzoj

洛谷

题解

考虑一个形如\(AABB\)的串是由两个形如\(AA\)的串拼起来的

那么我们设

\(f[i]\):以位置\(i\)为结尾的形如\(AA\)串的个数

\(g[i]\):以位置\(i\)为开头的形如\(AA\)串的个数

\[\therefore Ans=\sum_{i=1}^nf[i]*g[i+1]
\]

题目的难点转化为求\(f,g\)。

但是,其实我们只要\(O(n^2)\)暴力求一下就有\(95pts\)了,

所以我们接下来考虑最后的\(5pts\)怎么拿:

我们枚举\(A\)的长度\(len\)

将所有位置为\(len\)的倍数的点设为关键点,

则如果一个\(AA\)满足要求

这个\(AA\)必过两个关键点,

那么我们要算的就是相邻两个关键点对答案的贡献:

记相邻两个关键点为\(,i,j\)那么\(j=i+len\)

记\(Lcp=lcp(suf(i), suf(j)),Lcs=lcs(pre(i-1),pre(j-1))\)

那么,如果\(Lcp+Lcs<len\),则不能构成\(AA\)

为什么呢?

相当于这样一种情况:

\[\underbrace{.......i-1}_{Lcs}\;\overbrace{\underbrace{i........}_{Lcp}\;....\underbrace{.......j-1}_{Lcs}}^{len}\;\underbrace{j........}_{Lcp}
\]

这样子是不合法的。

反之,中间两段的\(Lcp,Lcs\)会有交,而我们这个\(A\)串的终点落在中间长度为\(Lcp+Lcs-len+1\)的交上都是可以的

因为这样的话平移一下可以保证紧跟着出现一个不重叠的\(A\)串

又因为串\(A\)起点和终点分别出现的位置是一段区间,所以直接分别在\(f,g\)上差分即可

复杂度是调和级数\(O(nlogn)\)。

具体细节看代码:

  1. #include <iostream>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <cmath>
  6. #include <algorithm>
  7. #include <map>
  8. using namespace std;
  9. inline int gi() {
  10. register int data = 0, w = 1;
  11. register char ch = 0;
  12. while (!isdigit(ch) && ch != '-') ch = getchar();
  13. if (ch == '-') w = -1, ch = getchar();
  14. while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
  15. return w * data;
  16. }
  17. const int MAX_N = 3e4 + 5;
  18. char a[MAX_N];
  19. int N, lg[MAX_N], f[MAX_N], g[MAX_N];
  20. struct SuffixArray {
  21. int sa[MAX_N], rnk[MAX_N], lcp[MAX_N];
  22. void buildSA() {
  23. #define cmp(i, j, k) (y[i] == y[j] && y[i + k] == y[j + k])
  24. static int x[MAX_N], y[MAX_N], bln[MAX_N];
  25. memset(sa, 0, sizeof(sa));
  26. memset(rnk, 0, sizeof(rnk));
  27. memset(lcp, 0, sizeof(lcp));
  28. memset(x, 0, sizeof(x));
  29. memset(y, 0, sizeof(y));
  30. memset(bln, 0, sizeof(bln));
  31. int M = 122;
  32. for (int i = 1; i <= N; i++) bln[x[i] = a[i]]++;
  33. for (int i = 1; i <= M; i++) bln[i] += bln[i - 1];
  34. for (int i = N; i >= 1; i--) sa[bln[x[i]]--] = i;
  35. for (int k = 1; k <= N; k <<= 1) {
  36. int p = 0;
  37. for (int i = 0; i <= M; i++) y[i] = 0;
  38. for (int i = N - k + 1; i <= N; i++) y[++p] = i;
  39. for (int i = 1; i <= N; i++) if (sa[i] > k) y[++p] = sa[i] - k;
  40. for (int i = 0; i <= M; i++) bln[i] = 0;
  41. for (int i = 1; i <= N; i++) bln[x[y[i]]]++;
  42. for (int i = 1; i <= M; i++) bln[i] += bln[i - 1];
  43. for (int i = N; i >= 1; i--) sa[bln[x[y[i]]]--] = y[i];
  44. swap(x, y); x[sa[1]] = p = 1;
  45. for (int i = 2; i <= N; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p;
  46. if (p >= N) break;
  47. M = p;
  48. }
  49. for (int i = 1; i <= N; i++) rnk[sa[i]] = i;
  50. for (int i = 1, j = 0; i <= N; i++) {
  51. if (j) j--;
  52. while (a[i + j] == a[sa[rnk[i] - 1] + j]) ++j;
  53. lcp[rnk[i]] = j;
  54. }
  55. }
  56. int st[16][MAX_N];
  57. void buildST() {
  58. memset(st, 63, sizeof(st));
  59. for (int i = 1; i <= N; i++) st[0][i] = lcp[i];
  60. for (int i = 1; i <= 15; i++)
  61. for (int j = 1; j <= N; j++)
  62. st[i][j] = min(st[i - 1][j], st[i - 1][j + (1 << (i - 1))]);
  63. }
  64. int query(int l, int r) {
  65. int _l = l, _r = r;
  66. l = min(rnk[_l], rnk[_r]) + 1, r = max(rnk[_l], rnk[_r]);
  67. int t = lg[r - l + 1];
  68. return min(st[t][l], st[t][r - (1 << t) + 1]);
  69. }
  70. } A, B;
  71. void Sol() {
  72. scanf("%s", a + 1); N = strlen(a + 1);
  73. A.buildSA(), A.buildST();
  74. reverse(&a[1], &a[N + 1]);
  75. B.buildSA(), B.buildST();
  76. memset(f, 0, sizeof(f));
  77. memset(g, 0, sizeof(g));
  78. for (int Len = 1; Len <= N / 2; Len++) {
  79. for (int i = Len, j = i + Len; j <= N; i += Len, j += Len) {
  80. int Lcp = min(A.query(i, j), Len), Lcs = min(B.query(N - i + 2, N - j + 2), Len - 1);
  81. int t = Lcp + Lcs - Len + 1;
  82. if (Lcp + Lcs >= Len) {
  83. g[i - Lcs]++, g[i - Lcs + t]--;
  84. f[j + Lcp - t]++, f[j + Lcp]--;
  85. }
  86. }
  87. }
  88. for (int i = 1; i <= N; i++) f[i] += f[i - 1], g[i] += g[i - 1];
  89. long long ans = 0;
  90. for (int i = 1; i < N; i++) ans += 1ll * f[i] * g[i + 1];
  91. printf("%lld\n", ans);
  92. }
  93. int main () {
  94. #ifndef ONLINE_JUDGE
  95. freopen("cpp.in", "r", stdin);
  96. #endif
  97. for (int i = 2; i <= 30000; i++) lg[i] = lg[i >> 1] + 1;
  98. int T; scanf("%d", &T);
  99. while (T--) Sol();
  100. return 0;
  101. }

【BZOJ4560】[NOI2016]优秀的拆分的更多相关文章

  1. [NOI2016]优秀的拆分&&BZOJ2119股市的预测

    [NOI2016]优秀的拆分 https://www.lydsy.com/JudgeOnline/problem.php?id=4650 题解 如果我们能够统计出一个数组a,一个数组b,a[i]表示以 ...

  2. luogu1117 [NOI2016]优秀的拆分

    luogu1117 [NOI2016]优秀的拆分 https://www.luogu.org/problemnew/show/P1117 后缀数组我忘了. 此题哈希可解决95分(= =) 设\(l_i ...

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

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

  4. [NOI2016]优秀的拆分(SA数组)

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

  5. 题解-NOI2016 优秀的拆分

    NOI2016 优秀的拆分 \(T\) 组测试数据.求字符串 \(s\) 的所有子串拆成 \(AABB\) 形式的方案总和. 数据范围:\(1\le T\le 10\),\(1\le n\le 3\c ...

  6. [NOI2016]优秀的拆分 后缀数组

    题面:洛谷 题解: 因为对于原串的每个长度不一定等于len的拆分而言,如果合法,它将只会被对应的子串统计贡献. 所以子串这个限制相当于是没有的. 所以我们只需要对于每个位置i求出f[i]表示以i为开头 ...

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

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

  8. [Noi2016]优秀的拆分

    来自F allDream的博客,未经允许,请勿转载,谢谢. 如果一个字符串可以被拆分为 AABB 的形式,其中 A和 B是任意非空字符串,则我们称该字符串的这种拆分是优秀的. 例如,对于字符串 aab ...

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

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

随机推荐

  1. js调用echarts getImage方法 将图表转换为img

    function chart(opt,id,chartName){//配置option的方法 var chartName = echarts.init(document.getElementById( ...

  2. echarts柱状图,改变柱状颜色

    在使用echarts产生的柱状图中,有时候自动产生的颜色大不如人意,可以通过以下参数进行修改. series : [ { name:'天数', type:'bar', stack: '天', data ...

  3. jquery实现的时间轴

    代码 样式文件style.css 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 ...

  4. BZOJ 1012 最大数maxnumber 线段树

    题目链接: https://www.lydsy.com/JudgeOnline/problem.php?id=1012 题目大意: 见链接 思路: 直接用线段树模拟一下就可以了. #include&l ...

  5. ClassNotFoundException: INameEnvironment

    springboot兼容jsp启动是报错,ClassNotFoundException: INameEnvironment 降低springboot版本即可,原版本1.5.10,降为1.5.2可使用

  6. BZOJ3791:作业(DP)

    Description 众所周知,白神是具有神奇的能力的. 比如说,他对数学作业说一声“数”,数学作业就会出于畏惧而自己完成:对语文作业说一声“语”,语文作业就会出于畏惧而自己完成. 今天,语文老师和 ...

  7. 【小M的作物】

    这是一道我好像没写过的最小割 这道题如果没有那\(m\)条限制,我们完全可以贪心来做 但是硬要用网络流怎么办 可以转化为最小割模型 我们将源点\(S\)表示为耕地\(A\),汇点\(T\)表示为耕地\ ...

  8. Mysql 用户权限管理--从 xxx command denied to user xxx

    今天遇到一个mysql 权限的问题,即标题所述  xxx command denied to user xxx,一般mysql 这种报错,基本都属于当前用户没有进行该操作的权限,需要 root 用户授 ...

  9. 五子棋项目总结 JavaScript+jQuery(插件写法)+bootstrap(模态框)

    Html部分(界面): 1.五子棋棋盘由canvas完成: 2.两个按钮,样式由bootstrap完成: 3.菜单按钮对应的模态框,可以选择游戏模式:玩家自由对战,和电脑对战,还可以指定谁先执子和哪个 ...

  10. 让PHP更快的提供文件下载

    一般来说, 我们可以通过直接让URL指向一个位于Document Root下面的文件, 来引导用户下载文件. 但是, 这样做, 就没办法做一些统计, 权限检查, 等等的工作. 于是, 很多时候, 我们 ...