题目链接

思路

观察题目中的式子,可以发现前两项是定值。所以只需要求出最后一项就行了。

然后题目就转化为了求字符串中所有后缀的\(lcp\)长度之和。

可以想到用后缀数组。在后缀数组上两个后缀的\(lcp\)长度表现为两个后缀排名之间的\(height\)的最小值。

所以现在问题就又转化为了在\(height\)数组上求所有区间最小值之和。

这个可以用单调栈做到。

代码

  1. /*
  2. * @Author: wxyww
  3. * @Date: 2019-01-30 19:14:49
  4. * @Last Modified time: 2019-01-30 20:49:38
  5. */
  6. #include<cstdio>
  7. #include<iostream>
  8. #include<cstdlib>
  9. #include<cstring>
  10. #include<cmath>
  11. #include<ctime>
  12. #include<bitset>
  13. using namespace std;
  14. typedef long long ll;
  15. #define int ll
  16. const int N = 500010;
  17. ll read() {
  18. ll x=0,f=1;char c=getchar();
  19. while(c<'0'||c>'9') {
  20. if(c=='-') f=-1;
  21. c=getchar();
  22. }
  23. while(c>='0'&&c<='9') {
  24. x=x*10+c-'0';
  25. c=getchar();
  26. }
  27. return x*f;
  28. }
  29. int sa[N],rk[N],height[N],c[N],x[N],y[N];
  30. char s[N];
  31. int m,n;
  32. void get_sa() {
  33. for(int i = 1;i <= m;++i) c[i] = 0;
  34. for(int i = 1;i <= n;++i) ++c[x[i] = s[i]];
  35. for(int i = 2;i <= m;++i) c[i] += c[i - 1];
  36. for(int i = n;i >= 1;--i) sa[c[x[i]]--] = i;
  37. for(int k = 1;k <= n;k <<= 1) {
  38. int num = 0;
  39. for(int i = n - k + 1;i <= n; ++i) y[++num] = i;
  40. for(int i = 1;i <= n;++i) if(sa[i] > k) y[++num] = sa[i] - k;
  41. for(int i = 2;i <= m;++i) c[i] = 0;
  42. for(int i = 1;i <= n;++i) ++c[x[i]];
  43. for(int i = 1;i <= m;++i) c[i] += c[i - 1];
  44. for(int i = n;i >= 1;--i) sa[c[x[y[i]]]--] = y[i];
  45. swap(x,y);
  46. num = 0;
  47. x[sa[1]] = ++num;
  48. for(int i = 2;i <= n;++i) {
  49. if(y[sa[i]] == y[sa[i - 1]] && y[sa[i] + k] == y[sa[i - 1] + k]) x[sa[i]] = num;
  50. else x[sa[i]] = ++num;
  51. }
  52. if(num == n) break;
  53. m = num;
  54. }
  55. }
  56. int h[N],q[N],tail;
  57. void get_height() {
  58. for(int i = 1;i <= n;++i) rk[sa[i]] = i;
  59. int k = 0;
  60. for(int i = 1;i <= n;++i) {
  61. if(rk[i] == 1) continue;
  62. if(k) --k;
  63. int j = sa[rk[i] - 1];
  64. while(j + k <= n && i + k <= n && s[j + k] == s[i + k]) ++k;
  65. h[i] = height[rk[i]] = k;
  66. }
  67. }
  68. ll work() {
  69. int tail = 0;
  70. ll now = 0,ans = 0;
  71. for(int i = 1; i <= n;++i) {
  72. while(height[i] < height[q[tail]] && tail) now -= height[q[tail]] * (q[tail] - q[tail - 1]),tail--;
  73. q[++tail] = i;
  74. now += height[i] * (q[tail] - q[tail - 1]);
  75. ans += now;
  76. }
  77. return ans;
  78. }
  79. int get(int x,int y) {
  80. int ans = 1e9;
  81. int l = min(rk[x],rk[y]),r = max(rk[x],rk[y]);
  82. for(int i = l + 1;i <= r;++i) ans = min(ans,height[i]);
  83. return ans;
  84. }
  85. signed main() {
  86. scanf("%s",s + 1);
  87. n = strlen(s + 1);
  88. m = 'z';
  89. get_sa();
  90. get_height();
  91. ll ans = 0;
  92. for(int i = 1;i <= n;++i)
  93. ans += i * (i - 1) + i * (n - i);
  94. ll LC = 2ll * work();
  95. cout<<ans - LC;
  96. return 0;
  97. }

bzoj3238 差异的更多相关文章

  1. [bzoj3238]差异(后缀数组+单调栈)

    显然我们可以先把len(Ti)+len(Tj)的值先算出来,再把LCP减去.所有len(Ti)+len(Tj)的值为n*(n-1)*(n+1)/2,这个随便在纸上画一画就可以算出来的. 接下来问题就是 ...

  2. 【BZOJ3238】差异(后缀自动机)

    [BZOJ3238]差异(后缀自动机) 题面 BZOJ 题解 前面的东西直接暴力算就行了 其实没必要算的正正好 为了方便的后面的计算 我们不考虑\(i,j\)的顺序问题 也就是先求出\(\sum_{i ...

  3. 【BZOJ3238】[AHOI2013]差异

    [BZOJ3238][AHOI2013]差异 题面 给定字符串\(S\),令\(T_i\)表示以它从第\(i\)个字符开始的后缀.求 \[ \sum_{1\leq i<j\leq n}len(T ...

  4. 【BZOJ3238】[Ahoi2013]差异 后缀数组+单调栈

    [BZOJ3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...

  5. bzoj3238 [Ahoi2013]差异 后缀数组+单调栈

    [bzoj3238][Ahoi2013]差异 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sample Ou ...

  6. [bzoj3238][Ahoi2013]差异_后缀数组_单调栈

    差异 bzoj-3238 Ahoi-2013 题目大意:求任意两个后缀之间的$LCP$的和. 注释:$1\le length \le 5\cdot 10^5$. 想法: 两个后缀之间的$LCP$和显然 ...

  7. BZOJ3238 [Ahoi2013]差异 【SAM or SA】

    BZOJ3238 [Ahoi2013]差异 给定一个串,问其任意两个后缀的最长公共前缀长度的和 1.又是后缀,又是\(lcp\),很显然直接拿\(SA\)的\(height\)数组搞就好了,配合一下单 ...

  8. 【BZOJ-3238】差异 后缀数组 + 单调栈

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1561  Solved: 734[Submit][Status] ...

  9. 【bzoj3238】 Ahoi2013—差异

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 (题目链接) 题意 给出一个字符串,求${\sum_{1<=i<j<=n} ...

随机推荐

  1. 关于wordpress更新提示无法创建目录问题

    说说自己的看法和解决办法 看法: 网上很多人说:是权限问题,那么将文件目录权限设置为777就可以解决.恩,没错,是可以解决更新问题,可是却带来了更大的问题——安全.像他们这个设置后,网站被攻破,数据被 ...

  2. Math java

    package cn.liuliu.com; import java.math.BigDecimal; import java.math.BigInteger; /* * 一.Math类? * * 1 ...

  3. 转载 -- jquery easyui datagrid 动态表头 + 嵌套对象属性展示

    代码功能: 1.datagrid 的表头由后台生成,可以配置在数据库 2.datagrid 的列绑定数据 支撑嵌套对象 $(function() { var columns = new Array() ...

  4. C-Lodop设置页面一加载就打印

    C-Lodop由于是服务不是np插件,调用打印语句(print或preview等)时机太早,在页面第一次加载完成后有几百毫秒时间等待WebSocket通讯服务准备完成,在没完成的时候会提示“C-Lod ...

  5. Linux下 rewrite_mod 的配置

    以下使用最新的 Ubuntu 16.04 测试; 安装好apache后先确认有没有rewrite模块,大多数情况下是有的:ls /etc/apache2/mods-available |grep re ...

  6. SVG路径

    前面的话 本文将详细介绍SVG路径 path字符串 路径(path)是一个非常强大的绘图工具,可以用path元素绘制矩形(直角矩形或者圆角矩形).圆形.椭圆.折线形.多边形,以及一些其他的形状,例如贝 ...

  7. faster rcnn讲解很细

    https://blog.csdn.net/bailufeiyan/article/details/50749694 https://www.cnblogs.com/dudumiaomiao/p/65 ...

  8. 动态追加js

    判断是否已引用js,如果没有会引发异常,在异常时添加引用 try { if (layui) {} } catch (ex) { var s = document.createElement('scri ...

  9. HDU3966-Aragorn's Story-树链剖分-点权

    很模板的树链剖分题 注意什么时候用线段树上的标号,什么时候用点的标号. #pragma comment(linker, "/STACK:102400000,102400000") ...

  10. python中的map函数

    def f(x): return x * x """将一个全是数字的list变成平方形式""" def f2(): ls = [1, 2, ...