都LCP了很显然是要用到后缀数组的

显然前面的那个东西是可以直接算出来的

关键在于LCP的和怎么快速的计算

不难想到穷举height[i],然后判断这个height[i]可能成为多少对后缀的LCP

考虑到LCP(i,j)=min(height[rank[i]+1~rank[j]]) 假定rank[i]<rank[j];

假设height[l]是左边第一个小于height[i]的,height[r]是右边第一个小于height[i]的

则height[i]是(i-l)(r-i)对后缀的LCP

但这样有一个问题,相同height可能会被重复计算

为了避免重复,我们定义height[r]是右边第一个不大于height[i]的

这样就有两种方法来实现

第一种是二分+rmq,但不幸的是我竟然写超时,而且我觉得容易出错

第二种是利用单调队列,我们把height[i]对应的l,r定义为左右边界,记为l[i],r[i];

计算左边界和右边界是相似的,这里我们讨论左边界

假如height[j]<=height[k] (j>k) 那么对于之后的height[i],

要么能延伸到k之前(height[i]<=height[j]),要么只能左边界就是j(height[i]>height[j]),不用比较height[k]

显然我们要维护一个单调不降的队列就行了

最后计算的时候注意用int64

 var rank,sa,y,q,x,sum,h,l,r:array[..] of longint;
    s:ansistring;
    i,n,m,p,j,t:longint;
    ans,z:int64; function min(a,b:longint):longint;
  begin
    if a>b then exit(b) else exit(a);
  end; procedure suffix;
  var i,j,p:longint;
  begin
    for i:= to n do
    begin
      y[i]:=ord(s[i]);
      inc(sum[y[i]]);
    end;
    m:=;
    for i:= to m do
      inc(sum[i],sum[i-]);
    for i:=n downto do
    begin
      sa[sum[y[i]]]:=i;
      dec(sum[y[i]]);
    end;
    p:=;
    rank[sa[]]:=;
    for i:= to n do
    begin
      if y[sa[i]]<>y[sa[i-]] then inc(p);
      rank[sa[i]]:=p;
    end;
    m:=p;
    j:=;
    while m<n do
    begin
      fillchar(sum,sizeof(sum),);
      y:=rank;
      p:=;
      for i:=n-j+ to n do
      begin
        inc(p);
        x[p]:=i;
      end;
      for i:= to n do
        if sa[i]>j then
        begin
          inc(p);
          x[p]:=sa[i]-j;
        end;       for i:= to n do
      begin
        rank[i]:=y[x[i]];
        inc(sum[rank[i]]);
      end;
      for i:= to m do
        inc(sum[i],sum[i-]);
      for i:=n downto do
      begin
        sa[sum[rank[i]]]:=x[i];
        dec(sum[rank[i]]);
      end;
      p:=;
      rank[sa[]]:=;
      for i:= to n do
      begin
        if (y[sa[i]]<>y[sa[i-]]) or (y[sa[i]+j]<>y[sa[i-]+j]) then inc(p);
        rank[sa[i]]:=p;
      end;
      m:=p;
      j:=j shl ;
    end;
    h[]:=;
    p:=;
    for i:= to n do
    begin
      if rank[i]= then continue;
      j:=sa[rank[i]-];
      while (i+p<=n) and (j+p<=n) and (s[i+p]=s[j+p]) do inc(p);
      h[rank[i]]:=p;
      if p> then dec(p);
    end;
  end; function calc(i,x,y:int64):int64;
  begin
    exit(*h[i]*(i-x)*(y-i));
  end; begin
  readln(s);
  n:=length(s);
  suffix;
  z:=n;
  ans:=(z+)*z div *(z-);
  t:=;
  for i:= to n do
  begin
    while (t>) and (h[q[t]]>=h[i]) do dec(t);
    if t= then l[i]:=
    else l[i]:=q[t];
    inc(t);
    q[t]:=i;
  end;
  t:=;
  for i:=n downto do
  begin
    while (t>) and (h[q[t]]>h[i]) do dec(t);  //注意右边界是第一个不大于的height,防止重复
    if t= then r[i]:=n+
    else r[i]:=q[t];
    inc(t);
    q[t]:=i;
  end;
  for i:= to n do
    ans:=ans-calc(i,l[i],r[i]);
  writeln(ans);
end.

bzoj3238的更多相关文章

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

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

  2. 【BZOJ3238】[AHOI2013]差异

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

  3. 【bzoj3238】 Ahoi2013—差异

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

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

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

  5. [BZOJ3238][AHOI2013]差异(后缀数组)

    求和式的前两项可以直接算,问题是对于每对i,j计算LCP. 一个比较显然的性质是,LCP(i,j)是h[rk[i]+1~rk[j]]中的最小值. 从h的每个元素角度考虑,就是对每个h计算有多少对i,j ...

  6. [BZOJ3238][Ahoi2013]差异解题报告|后缀数组

    Description 先分析一下题目,我们显然可以直接算出sigma(len[Ti]+len[Tj])的值=(n-1)*n*(n+1)/2 接着就要去算这个字符串中所有后缀的两两最长公共前缀总和 首 ...

  7. 【bzoj3238】差异[AHOI2013](后缀数组+单调栈)

    题目传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3238 这道题从大概半年以前就开始啃了,不过当时因为一些细节没调出来,看了Sakits神犇 ...

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

    题目链接 BZOJ3238 题解 简单题 经典后缀数组 + 单调栈套路,求所有后缀\(lcp\) #include<iostream> #include<cstdio> #in ...

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

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

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

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

随机推荐

  1. Linq 与UnitOfWork

    submitchages(linq to sql)或者savechanges(ef)的次数是根据你操作方法的数量决定的,也即是:它只认识自己的提交语句(submtchanges,savechanges ...

  2. VS中使用sqlite静态连接

    说明 最近写的文章有些多,懒得打字了,就直接上文章.这里说明一下,我说的是VS,不是指定的哪一个VS版本.先下载官方的源文件:sqlite-amalgamation-3071502.zip 下载下来的 ...

  3. C# 时间与时间戳互转

    /// <summary> /// 将c# DateTime时间格式转换为Unix时间戳格式 /// </summary> /// <param name="t ...

  4. 『奇葩问题集锦』Fedora ubuntu 下使用gulp 报错 Error: watch ENOSPC 解决方案

    用gulp启动,错误如下 Error: watch ENOSPC at exports._errnoException (util.js:746:11) at FSWatcher.start (fs. ...

  5. 大量字段表单在PHP便捷处理分享

    关于程序开发中的表单批量提交策略很多时候一个表单太多的字段,如何能够高效获取表单字段,也为如何提神开发的效率和统一性? 比如一个系统的某个有26个字段,那么我用表单的名称用26个a到z的字母, 你是选 ...

  6. 10分钟进阶Nuget

    nuget是什么 .net版的maven(java)? 如果你用过windows的chocolatey,mac的homebrew或许更容易理解他,先来回顾下以前我们是如何处理或者碰到过的问题. 1.假 ...

  7. word 2013 没有控件菜单怎么办,添加控件菜单

    方法/步骤   打开word软件,然后点击菜单栏中最左边的“文件”菜单项,如下图红色方框所示 2 点击文件后,就打开word的设置对话框,然后在左边的设置列表中点击“自定义功能区”,打开自定义功能区设 ...

  8. Windows API 常量定义

    Windows 常量定义在winuser.h中可以找到,如果了安装了visual studio 2010,winuser.h所在目录为C:\Program Files (x86)\Microsoft ...

  9. C语言-06复杂数据类型-03指针

    指针变量的定义 变量类型 *变量名; #include <stdio.h> int main() { // 指针就一个作用:能够根据一个地址值,访问对应的存储空间 // 指针变量p前面的i ...

  10. Marsonry

    前言 1 MagicNumber -> autoresizingMask -> autolayout 以上是纯手写代码所经历的关于页面布局的三个时期 在iphone1-iphone3gs时 ...