[传送门[(https://www.lydsy.com/JudgeOnline/problem.php?id=3238)

解题思路

  首先原式可以把\(len\)那部分直接算出来,然后通过后缀数组求\(lcp\)。算\(\sum lcp\)的时候,刚开始傻了想要直接算贡献,结果越写越乱,后来想想只需要用单调栈把每个点的控制范围算出来即可,正着做一遍反着做一遍。注意还要考虑两个\(h[i]\)相邻并相等时的影响。还有一种比较自然的解法是后缀树,\(lcp\)其实就为两个点的\(lca\)的深度,所以建出后缀树后直接按拓扑序\(dp\)一下即可。

代码

后缀数组:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib> using namespace std;
const int MAXN = 500005;
typedef long long LL; int n,m,height[MAXN],num,stk[MAXN],top,l[MAXN],r[MAXN];
int sa[MAXN],rk[MAXN],x[MAXN<<1],y[MAXN<<1],c[MAXN];
char s[MAXN];
LL ans; inline void get_SA(){
for(int i=1;i<=n;i++) x[i]=s[i],c[x[i]]++;
for(int i=2;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[x[i]]--]=i;
for(int k=1;k<=n;k<<=1){num=0;
for(int i=n-k+1;i<=n;i++) y[++num]=i;
for(int i=1;i<=n;i++) if(sa[i]>k) y[++num]=sa[i]-k;
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++) c[x[i]]++;
for(int i=2;i<=m;i++) c[i]+=c[i-1];
for(int i=n;i;i--) sa[c[x[y[i]]]--]=y[i],y[i]=0;
swap(x,y);num=1;x[sa[1]]=1;
for(int i=2;i<=n;i++)
x[sa[i]]=(y[sa[i]]==y[sa[i-1]] && y[sa[i]+k]==y[sa[i-1]+k])?num:++num;
if(num==n) break;m=num;
}
} inline void get_height(){
for(int i=1;i<=n;i++) rk[sa[i]]=i;int j,k=0;
for(int i=1;i<=n;i++){
if(rk[i]==1) continue;
if(k) k--;j=sa[rk[i]-1];
while(i+k<=n && j+k<=n && s[i+k]==s[j+k]) k++;
height[rk[i]]=k;
}
} void solve(){
for(int i=1;i<=n;i++){
while(top && height[i]<=height[stk[top]]) l[stk[top]]=i-1,top--;
if(height[i]) stk[++top]=i;
}
while(top) l[stk[top--]]=n;
for(int i=n;i;i--){
while(top && height[i]<height[stk[top]]) r[stk[top]]=i+1,top--;
if(height[i]) stk[++top]=i;
}
while(top) r[stk[top--]]=1;
for(int i=1;i<=n;i++) ans-=(LL)height[i]*(l[i]-i+1)*(i-r[i]+1)*2;
} int main(){
scanf("%s",s+1);n=strlen(s+1);m='z';
get_SA();get_height();
// for(int i=1;i<=n;i++) cout<<sa[i]<<" ";cout<<endl;
// for(int i=1;i<=n;i++) cout<<height[i]<<" ";cout<<endl;
ans=(LL)n*(n-1)/2*(n+1);
solve();printf("%lld\n",ans);
return 0;
}

后缀树:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#define int long long using namespace std;
const int MAXN = 500005<<1;
typedef long long LL; char s[MAXN];
int n,siz[MAXN],lst,cnt;
int fa[MAXN],ch[MAXN][27],l[MAXN],a[MAXN],c[MAXN];
LL ans; inline void Insert(int c){
int p=lst,np=++cnt;lst=np;l[np]=l[p]+1;
for(;p && !ch[p][c];p=fa[p]) ch[p][c]=np;
if(!p) fa[np]=1;
else{
int q=ch[p][c];
if(l[q]==l[p]+1) fa[np]=q;
else {
int nq=++cnt;l[nq]=l[p]+1;
memcpy(ch[nq],ch[q],sizeof(ch[q]));
fa[nq]=fa[q];fa[q]=fa[np]=nq;
for(;ch[p][c]==q;p=fa[p]) ch[p][c]=nq;
}
}
siz[np]=1;
} signed main(){
scanf("%s",s+1);n=strlen(s+1);lst=cnt=1;
for(int i=n;i;i--) Insert(s[i]-'a'+1);
ans=(LL)n*(n-1)/2*(n+1);
for(int i=1;i<=cnt;i++) c[l[i]]++;
for(int i=1;i<=cnt;i++) c[i]+=c[i-1];
for(int i=1;i<=cnt;i++) a[c[l[i]]--]=i;
for(int i=cnt;i;i--){
ans-=(LL)siz[a[i]]*siz[fa[a[i]]]*l[fa[a[i]]]*2;
siz[fa[a[i]]]+=siz[a[i]];
}
printf("%lld\n",ans);
return 0;
}

BZOJ 3238: [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 MB Description Input 一行,一个字符串S Output 一行,一个 ...

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

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

  4. bzoj 3238 Ahoi2013 差异

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

  5. BZOJ.3238.[AHOI2013]差异(后缀自动机 树形DP/后缀数组 单调栈)

    题目链接 \(Description\) \(Solution\) len(Ti)+len(Tj)可以直接算出来,每个小于n的长度会被计算n-1次. \[\sum_{i=1}^n\sum_{j=i+1 ...

  6. ●BZOJ 3238 [Ahoi2013]差异

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=3238 题解: 后缀数组套路深. 问题转化为求出任意两个后缀的LCP之和 在计算贡献时,各种不 ...

  7. 洛谷 P4248: bzoj 3238: [AHOI2013]差异

    题目传送门:洛谷 P4248. 题意简述: 定义两个字符串 \(S\) 和 \(T\) 的差异 \(\operatorname{diff}(S,T)\) 为这两个串的长度之和减去两倍的这两个串的最长公 ...

  8. BZOJ 4826: [Hnoi2017]影魔 单调栈+可持久化线段树

    Description 影魔,奈文摩尔,据说有着一个诗人的灵魂.事实上,他吞噬的诗人灵魂早已成千上万.千百年来,他收集了各式各样 的灵魂,包括诗人.牧师.帝王.乞丐.奴隶.罪人,当然,还有英雄.每一个 ...

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

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3238 [题目大意] 给出一个串,设T[i]表示从第i位开始的后缀, 求sum(len( ...

随机推荐

  1. vue实现前后台交互

    首先需要前台先安装一个包 cnpm install axios --save 第二还需要解决跨域问题 在settings中添加一条中间件 MIDDLEWARE = [“corsheders.middl ...

  2. python--表达式形式的yield、面向过程编程、内置函数

    yield的表达式形式 def init(func): def wrapper(*args, **kwargs): g = func(*args, **kwargs) next(g) return g ...

  3. Python面向对象 杂篇(后记)

    异常处理 什么是异常:         我们在调试程序时,常常会因为各种报错信息导致程序无法运行,异常也是一个对象,用来表示错误.我们可以捕捉异常,并做相应处理,从而增加代码的友好程度. 异常处理: ...

  4. jenkins安装-配置

    jenkins安装-配置 注意: jenkins访问 用chrome浏览器 安装包下载:http://pkg.jenkins-ci.org/redhat/ (使用2.92版本的) 安装jdk: 1.8 ...

  5. 探索Redis设计与实现4:Redis内部数据结构详解——ziplist

    本文转自互联网 本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial ...

  6. 【转】开源框架是如何通过JMX来做监控的(一) - JMX简介和Standard MBean

    原文链接:https://www.cnblogs.com/trust-freedom/p/6842332.html#autoid-0-0-0 相信很多做Java开发的同学都使用过JDK自带的 jcon ...

  7. java部署系列:CentOS下部署Java7/Java8

    一.前言 1.本文主要内容 CentOS下部署OracleJDK CentOS下部署OpenJDK 2.适用范围与本篇环境 适用范围 1.CentOS 6+2.Java 7+ 本篇环境 1.CentO ...

  8. Shell判断某文件夹下是否存在xxx开头的字符串

    Usage: bash judge_prefix_string.sh TARGET_DIR TARGET_STR #!/bin/bash TARGET_DIR=$1 TARGET_STR=$2 ls ...

  9. Kotlin 和 Flutter 对于开发者究竟意味着什么?

    更多阿里P7架构进阶学习视频:阿里P7Android架构进阶学习视频回放近些年来,编程语言流行度的变化其实不大,在 TIOBE 编程语言排行榜上,Java.C.C++ 固若金山,也就只有 Python ...

  10. mysql 5.7.20 从frm文件中得到建表语句 (使用 mysql-utilities)

    系统环境  centos 7.2    mysql社区版 5.7.20 mysql-utilities 根据官网的说法,截止到2018年5月30日,实用工具的一些功能在Shell的路线图中,鼓励用户迁 ...