题目分析:

求出height以后很明显跨越最小height的一定贡献是最小height,所以对于区间找出最小height再将区间对半分。

代码:

 #include<bits/stdc++.h>
using namespace std; const int maxn = ;
const int N = ; int n;
char str[maxn]; int sa[maxn],rk[maxn],X[maxn],Y[maxn];
int height[maxn],h[maxn],RMQ[maxn][],pos[maxn][]; int chk(int x,int k){
return rk[sa[x]]==rk[sa[x-]]&&rk[sa[x]+(<<k)]==rk[sa[x-]+(<<k)];
} void getsa(){
for(int i=;i<n;i++) X[str[i]]++;
for(int i=;i<=N;i++) X[i] += X[i-];
for(int i=n-;i>=;i--) sa[X[str[i]]--] = i;
for(int i = , num = ;i <= n;i++)
rk[sa[i]] = (str[sa[i]] == str[sa[i-]]?num:++num);
rk[sa[]] = ;
for(int k=;(<<k-)<=n;k++){
for(int i=;i<=N;i++) X[i] = ;
for(int i=n-(<<k-);i<n;i++) Y[i-n+(<<k-)+]=i;
for(int i=,j=(<<k-)+;i<=n;i++)
if(sa[i]>=(<<k-))Y[j++]=sa[i]-(<<k-);
for(int i=;i<n;i++) X[rk[i]]++;
for(int i=;i<=N;i++) X[i]+=X[i-];
for(int i=n;i>=;i--) sa[X[rk[Y[i]]]--] = Y[i];
int num = ; Y[sa[]] = ;
for(int i=;i<=n;i++) Y[sa[i]] = (chk(i,k-)?num:++num);
for(int i=;i<n;i++) rk[i] = Y[i];
if(num == n) break;
}
}
void getheight(){
for(int i=;i<n;i++){
if(i) h[i] = max(,h[i-]-); else h[i] = ;
if(rk[i] == ) continue;
int comp = sa[rk[i]-];
while(str[comp+h[i]] == str[i+h[i]])h[i]++;
}
for(int i=;i<n;i++) height[rk[i]] = h[i];
for(int i=;i<=n;i++) RMQ[i][] = height[i],pos[i][] = i;
for(int k=;(<<k)<=n;k++){
for(int i=;i<=n;i++){
if(i+(<<k-)>n) RMQ[i][k]=RMQ[i][k-],pos[i][k]=pos[i][k-];
else {
if(RMQ[i][k-]<RMQ[i+(<<k-)][k-]) pos[i][k] = pos[i][k-];
else pos[i][k] = pos[i+(<<k-)][k-];
RMQ[i][k] = min(RMQ[i][k-],RMQ[i+(<<k-)][k-]);
}
}
}
}
int getLCP(int L,int R){
if(L > R) swap(L,R);
if(L == R) return n-sa[L];
L++;
int k = ; while((<<k+)<=R-L+)k++;
if(RMQ[L][k]<RMQ[R-(<<k)+][k]) return pos[L][k];
else return pos[R-(<<k)+][k];
} long long ans = ; void divide(int l,int r){
if(l == r) return;
int ps = getLCP(l,r);
ans -= 2ll*(ps-l)*(r-ps+)*height[ps];
divide(l,ps-); divide(ps,r);
} void work(){
n = strlen(str);
getsa();
getheight();
for(int i=;i<=n;i++) ans += 1ll*i*i-i;
for(int i=;i<=n;i++) ans += 1ll*i*(n-i);
divide(,n);
printf("%lld\n",ans);
} int main(){
scanf("%s",str);
work();
return ;
}

AHOI2013 差异 【后缀数组】的更多相关文章

  1. bzoj 3238: [Ahoi2013]差异 -- 后缀数组

    3238: [Ahoi2013]差异 Time Limit: 20 Sec  Memory Limit: 512 MB Description Input 一行,一个字符串S Output 一行,一个 ...

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

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

  3. [AHOI2013] 差异 - 后缀数组,单调栈

    [AHOI2013] 差异 Description 求 \(\sum {len(T_i) + len(T_j) - 2 lcp(T_i,T_j)}\) 的值 其中 \(T_i (i = 1,2,... ...

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

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

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

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

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

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

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

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

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

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

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

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

  10. [Ahoi2013]差异(后缀自动机)

    /* 前面的那一坨是可以O1计算的 后面那个显然后缀数组单调栈比较好写??? 两个后缀的lcp长度相当于他们在后缀树上的lca的深度 那么我们就能够反向用后缀自动机构造出后缀树然后统计每个点作为lca ...

随机推荐

  1. Python_查找员工信息-48

    ''' 查找出userinfo文件中年龄大于22岁的员工姓名和年龄 1,Alex,22,13651054608,IT 2,Egon,23,13304320533,Tearcher 3,nezha,25 ...

  2. H5 40-CSS精灵图

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  3. ElasticSearch(简称ES)

    Windows下安装ElasticSearch   ElasticSearch(简称ES)是一个基于Lucene的分布式全文搜索服务器,和SQL Server的全文索引(Fulltext Index) ...

  4. 03-Linux的shell命令 .doc

    快捷键 基本操作和命令 Cd转换文件夹 以/开头的是绝对路径 没有/相对路径 ../代表上一级目录 Tab补充 Ctrl+R 查找历史输入过的命令 箭头上也代表能够查询以往输入的命令 Ctrl+C 终 ...

  5. vim 永久添加行号

    sudo vi /etc/vim/vimrc 打开vimrc文件,最下面添加set nu,保存就可以添加行号了,set autoindent是自动换行

  6. Dockers 学习

    Docker镜像操作,有五个常用的命令: a.拉取镜像,后跟镜像仓库名称,如果要指定某个版本,可以带上tag. > docker pull <repo>[:tag] b.列出所有镜像 ...

  7. windows中dir命令

    最近想用dos命令打印指定目录下的所有文件夹的完整路径.最终发现可用dir命令来实现.在此学习下dir的各项命令. 32位win7系统上,打印帮助文档. D:\test>dir /? 显示目录中 ...

  8. Azure系列2.1.6 —— BlobProperties

    (小弟自学Azure,文中有不正确之处,请路过各位大神指正.) 网上azure的资料较少,尤其是API,全是英文的,中文资料更是少之又少.这次由于公司项目需要使用Azure,所以对Azure的一些学习 ...

  9. [转帖]Oracle 裁员史:技术人死于重组,卒于云计算

    Oracle 裁员史:技术人死于重组,卒于云计算 https://www.infoq.cn/article/tm-mcdHCPCI4eEwr6dbY 大厂裁员 我妈妈也总担心我没工作了 怎么还房贷 田 ...

  10. [转帖]K8H3D 病毒 腾讯御剑的解析

    https://weibo.com/ttarticle/p/show?id=2309404344350225132710 永恒之蓝下载器木马又双叒叕升级了新的攻击方式​​ 背景 腾讯安全御见威胁情报中 ...