题意

考虑式子前面那段其实是\((n-1)*\frac{n*(n+1)}{2}\),因为每个后缀出现了\(n-1\)次,后缀总长为\(\frac{n*(n+1)}{2}\)。

现在考虑后面怎么求:

\(\sum\limits_{i=1}^{n}\sum\limits_{j=i+1}^nlcp(sa_i,sa_j)\)

我们知道后面那个可以转化成\(height\)数组的\(RMQ\)问题,于是我们转而考虑每个\(height_i\)的贡献。

我们对于每个\(i\)找到左边第一个小于\(height_i\)的位置\(j\),右边第一个小于等于\(height_i\)的位置\(k\)(注意条件不同,避免计重),那么\(height_i\)的贡献即为\(height_i*(i-j)*(k-i)\)

这个找的过程显然可以单调栈解决,注意\(height\)从\(2\)开始算(因为\([l,r]\)的\(height\)从\(l+1\)开始,这题所有数据的\(height_1\)都是\(0\),所以能过)。

code:

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. typedef long long ll;
  4. const int maxn=500010;
  5. int n,m,top;
  6. int sa[maxn],rk[maxn],oldrk[maxn],id[maxn],tmpid[maxn],cnt[maxn],height[maxn],sta[maxn],L[maxn],R[maxn];
  7. char s[maxn];
  8. inline bool check(int x,int y,int k){return oldrk[x]==oldrk[y]&&oldrk[x+k]==oldrk[y+k];}
  9. inline void sa_build()
  10. {
  11. m=300;
  12. for(int i=1;i<=n;i++)cnt[rk[i]=s[i]]++;
  13. for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
  14. for(int i=n;i;i--)sa[cnt[rk[i]]--]=i;
  15. for(int t=1;t<=n;t<<=1)
  16. {
  17. int tot=0;
  18. for(int i=n-t+1;i<=n;i++)id[++tot]=i;
  19. for(int i=1;i<=n;i++)if(sa[i]>t)id[++tot]=sa[i]-t;
  20. tot=0;
  21. memset(cnt,0,sizeof(cnt));
  22. for(int i=1;i<=n;i++)cnt[tmpid[i]=rk[id[i]]]++;
  23. for(int i=1;i<=m;i++)cnt[i]+=cnt[i-1];
  24. for(int i=n;i;i--)sa[cnt[tmpid[i]]--]=id[i];
  25. memcpy(oldrk,rk,sizeof(rk));
  26. for(int i=1;i<=n;i++)rk[sa[i]]=check(sa[i-1],sa[i],t)?tot:++tot;
  27. m=tot;
  28. if(m==n)break;
  29. }
  30. for(int i=1,j=0;i<=n;i++)
  31. {
  32. if(j)j--;
  33. while(s[i+j]==s[sa[rk[i]-1]+j])j++;
  34. height[rk[i]]=j;
  35. }
  36. }
  37. inline ll calc()
  38. {
  39. ll res=0;
  40. sta[++top]=1;
  41. for(int i=2;i<=n;i++)
  42. {
  43. while(top&&height[sta[top]]>=height[i])R[sta[top--]]=i;
  44. L[i]=sta[top];
  45. sta[++top]=i;
  46. }
  47. while(top)R[sta[top--]]=n+1;
  48. for(int i=2;i<=n;i++)res+=1ll*height[i]*(i-L[i])*(R[i]-i);
  49. return res;
  50. }
  51. int main()
  52. {
  53. scanf("%s",s+1);n=strlen(s+1);
  54. sa_build();
  55. printf("%lld\n",1ll*(n-1)*n*(n+1)/2-2*calc());
  56. return 0;
  57. }

luoguP4248 [AHOI2013]差异的更多相关文章

  1. BZOJ 3238: [Ahoi2013]差异 [后缀数组 单调栈]

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

  2. bzoj 3238 Ahoi2013 差异

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

  3. BZOJ 3238: [Ahoi2013]差异 [后缀自动机]

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

  4. BZOJ_3238_[Ahoi2013]差异_后缀自动机

    BZOJ_3238_[Ahoi2013]差异_后缀自动机 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao Sam ...

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

    BZOJ_3238_[Ahoi2013]差异_后缀数组+单调栈 Description Input 一行,一个字符串S Output 一行,一个整数,表示所求值 Sample Input cacao ...

  6. 【LG4248】[AHOI2013]差异

    [LG4248][AHOI2013]差异 题面 洛谷 题解 后缀数组版做法戳我 我们将原串\(reverse\),根据后缀自动机的性质,两个后缀的\(lcp\)一定是我们在反串后两个前缀的\(lca\ ...

  7. 【BZOJ3238】[AHOI2013]差异

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

  8. P4248 [AHOI2013]差异 解题报告

    P4248 [AHOI2013]差异 题目描述 给定一个长度为 \(n\) 的字符串 \(S\),令 \(T_i\) 表示它从第 \(i\) 个字符开始的后缀.求 \[\displaystyle \s ...

  9. 【BZOJ 3238】 3238: [Ahoi2013]差异(SAM)

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3047  Solved: 1375 Description In ...

随机推荐

  1. windows10安装最新的redis

    官方给的redis的windows版本最新为3,而linux版本是5 这里通过win10子系统安装,win10子系统的配置见另一篇博客https://www.cnblogs.com/MC-Curry/ ...

  2. postgresql 笔记

    客户端GUI 在官网下载一个,在安装的时候,不安装 server 端,会在客户端 安装一个 pgadmin .

  3. vscode源码分析【四】程序启动的逻辑,最初创建的服务

    第一篇: vscode源码分析[一]从源码运行vscode 第二篇:vscode源码分析[二]程序的启动逻辑,第一个窗口是如何创建的 第三篇:vscode源码分析[三]程序的启动逻辑,性能问题的追踪 ...

  4. 安装torch

    一.实验环境 1.Windows7x64_SP1 2.anaconda3.7 + python3.7(anaconda集成,不需单独安装) 二.问题描述 1.使用如下命令进行安装: pip3 inst ...

  5. 分词 | 双向匹配中文分词算法python实现

    本次实验内容是基于词典的双向匹配算法的中文分词算法的实现.使用正向和反向最大匹配算法对给定句子进行分词,对得到的结果进行比较,从而决定正确的分词方法. 算法描述正向最大匹配算法先设定扫描的窗口大小ma ...

  6. win7系统下安装Ubuntu18.04组成双系统

    最近在闲鱼上花了350大洋淘到了一台tinkpad sl510,这大概是一台发布于2009年的一台电脑了吧,处理器是酷睿二t440,2Gddr3的显卡,让我有点意外的是这台电脑的硬盘是7200转的32 ...

  7. KeContextToKframes函数逆向

    在逆向_KiRaiseException(之后紧接着就是派发KiDispatchException)函数时,遇到一个 KeContextToKframes 函数,表面意思将CONTEXT转换为 TRA ...

  8. CAS(比较并交换)

    一.CAS(无锁的执行者) CAS包含3个参数:内存值  V 旧的预期值  A 新值  B 当且仅当V值等于A值时,将V的值改为B值,如果V值和A值不同,说明已经有其他线程做了更新,则当前线程什么都不 ...

  9. npm命令集合

    1.npm初始化项目:npm init 或者 npm init --yes 生产 package.json文件 2.下载package.json安装包: npm install 缩写 npm i

  10. window启动webpack打包的三种方法

    1.在cmd终端执行 npx webpack命令 2.在package.json文件同级建立webpack.config.js文件,内容如下: const path = require('path') ...