Description

Input

一行,一个字符串S

Output

一行,一个整数,表示所求值

Sample Input

cacao

Sample Output

54

HINT

2<=N<=500000,S由小写英文字母组成

YY了后缀自动机的解法:

首先题意就是让你求sigma(LCP(i,j)|i<j)

将字符串反过来,考虑两个后缀对答案的贡献,其实就是节点x和y的lca节点包含的最长子串长度

那么将SAM构出来,考虑当LCA为节点z时,有多少满足条件的(x,y),这个枚举z的相邻子节点,dp一下即可

code:O(n) 2104ms

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=;
int n,to[maxn][],fa[maxn],l[maxn],f[maxn],x[maxn],w[maxn],od[maxn],cnt=,last=;
void extend(int c)
{
int p,q,np,nq;
p=last;last=np=++cnt;l[np]=l[p]+;f[np]=w[np]=;
for(;!to[p][c];p=fa[p]) to[p][c]=np;
if(!p) fa[np]=;
else
{
q=to[p][c];
if(l[p]+==l[q]) fa[np]=q;
else
{
nq=++cnt;l[nq]=l[p]+;
memcpy(to[nq],to[q],sizeof(to[q]));
fa[nq]=fa[q];
fa[q]=fa[np]=nq;
for(;to[p][c]==q;p=fa[p]) to[p][c]=nq;
}
}
}
LL solve()
{
LL ans=;
for(int i=;i<=cnt;i++) x[l[i]]++;
for(int i=;i<=n;i++) x[i]+=x[i-];
for(int i=;i<=cnt;i++) od[x[l[i]]--]=i;
for(int i=cnt;i;i--) f[fa[od[i]]]+=f[od[i]];
for(int i=;i<=cnt;i++)
{
ans+=(LL)w[fa[i]]*f[i]*l[fa[i]];
w[fa[i]]+=f[i];
}
return ans;
}
char s[maxn];
int main()
{
scanf("%s",s);
n=strlen(s);
for(int i=n-;i>=;i--) extend(s[i]-'a');
LL ans=;
for(int i=;i<=n;i++) ans+=(LL)i*(n-);
printf("%lld\n",ans-*solve());
return ;
}

另外转一下hzwer的SA解法:

--------------------------------------------------------------------------------------------------------------------------------------------蒟蒻与神犇的分界线--------------------------------------------

显然后缀数组不是正确姿势。。。

不过还是说说后缀数组的做法吧,bzoj总时限20s是能过的

SA+rmq求lcp应该烂大街了,这题还不用rmq。。。

首先求出h数组

考虑h[i]在哪些区间内会成为最小值,这个用两次单调栈很容易就能解决

还要处理一下由于h[i]可能相同造成的重复计数问题,具体看代码

code O(nlogn) 13592ms

#include<set>
#include<map>
#include<ctime>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 500005
#define inf 1000000000
#define pa pair<int,int>
#define ll long long
using namespace std;
ll ans;
int n,k,p,q=,top;
int v[N],a[N],h[N],sa[][N],rk[][N];
int st[N],l[N],r[N];
char ch[N];
void mul(int *sa,int *rk,int *SA,int *RK)
{
for(int i=;i<=n;i++)v[rk[sa[i]]]=i;
for(int i=n;i;i--)
if(sa[i]>k)
SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+;i<=n;i++)SA[v[rk[i]]--]=i;
for(int i=;i<=n;i++)
RK[SA[i]]=RK[SA[i-]]+(rk[SA[i-]]!=rk[SA[i]]||rk[SA[i-]+k]!=rk[SA[i]+k]);
}
void presa()
{
for(int i=;i<=n;i++)v[a[i]]++;
for(int i=;i<=;i++)v[i]+=v[i-];
for(int i=;i<=n;i++)sa[p][v[a[i]]--]=i;
for(int i=;i<=n;i++)
rk[p][sa[p][i]]=rk[p][sa[p][i-]]+(a[sa[p][i-]]!=a[sa[p][i]]);
for(k=;k<n;k<<=,swap(p,q))
mul(sa[p],rk[p],sa[q],rk[q]);
for(int k=,i=;i<=n;i++)
{
int j=sa[p][rk[p][i]-];
while(ch[j+k]==ch[i+k])k++;
h[rk[p][i]]=k;if(k>)k--;
}
}
void solve()
{
for(int i=;i<=n;i++)ans+=(ll)i*(n-);
h[]=-inf;
for(int i=;i<=n;i++)
{
while(h[i]<=h[st[top]])top--;
if(st[top]==)l[i]=;
else l[i]=st[top]+;
st[++top]=i;
}
h[n+]=-inf;top=;st[]=n+;
for(int i=n;i;i--)
{
while(h[i]<h[st[top]])top--;
if(st[top]==n+)r[i]=n;
else r[i]=st[top]-;
st[++top]=i;
}
for(int i=;i<=n;i++)
ans-=2LL*(i-l[i]+)*(r[i]-i+)*h[i];
}
int main()
{
scanf("%s",ch+);
n=strlen(ch+);
for(int i=;i<=n;i++)a[i]=ch[i]-'a'+;
presa();
solve();
printf("%lld",ans);
return ;
}

BZOJ3238: [Ahoi2013]差异 (后缀自动机)的更多相关文章

  1. [bzoj3238][Ahoi2013]差异——后缀自动机

    Brief Description Algorithm Design 下面给出后缀自动机的一个性质: 两个子串的最长公共后缀,位于这两个串对应的状态在parent树上的lca状态上.并且最长公共后缀的 ...

  2. BZOJ3238: [Ahoi2013]差异(后缀自动机)

    题意 题目链接 Sol 前面的可以直接算 然后原串翻转过来,这时候变成了求任意两个前缀的最长公共后缀,显然这个值应该是\(len[lca]\),求出\(siz\)乱搞一下 #include<bi ...

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

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

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

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

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

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

  6. 洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)

    题目见此 题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的 ...

  7. BZOJ 3238 [Ahoi2013]差异 ——后缀自动机

    后缀自动机的parent树就是反串的后缀树. 所以只需要反向构建出后缀树,就可以乱搞了. #include <cstdio> #include <cstring> #inclu ...

  8. [AHOI2013]差异 后缀自动机_Parent树

    题中要求: $\sum_{1\leqslant i < j \leq n } Len(T_{i}) +Len(T_{j})-2LCP(T_{i},T_{j})$ 公式左边的部分很好求,是一个常量 ...

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

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

  10. BZOJ 3238: [Ahoi2013]差异 后缀自动机 树形dp

    http://www.lydsy.com/JudgeOnline/problem.php?id=3238 就算是全局变量,也不要忘记,初始化(吐血). 长得一副lca样,没想到是个树形dp(小丫头还有 ...

随机推荐

  1. 【SpringMVC】SpringMVC系列4之@RequestParam 映射请求参数值

    4.@RequestParam 映射请求参数值 4.1.概述     Spring MVC 通过分析处理方法的签名,将 HTTP 请求信息绑定到处理方法的相应人参中.Spring MVC 对控制器处理 ...

  2. Windows metro app wcf 地址可配置

    在Windows metro app中调用wcf服务可以通过添加 “服务引用”来实现.一旦项目发布则不可修改.这个和桌面开发不一样. 现在我们通过读取文本的方式来读取wcf地址. 1.添加所需引用的w ...

  3. Powershell 批量替换文件

    Powershell 批量替换文件 ##作者:Xiongpq ##时间:2015-06-10 18:50 ##版本:2.0 ##源文件目录 ##源文件目录的所有文件都会覆盖目标目录的同名文件,源文件目 ...

  4. sublime text3侧边栏主题不生效问题解决

    sublime text3主题插件: Seti_UI 插件安装: 在线安装:需要FQ window: ctrl+shift+p 找install package:之后搜索 Seti_UI 安装完成后需 ...

  5. vs c++中读取数据流并存储

    ifstream in("test.txt"); vector<string> vs; string s; while(!in.eof()) { in>>s ...

  6. ajax(ajax开发与入门)

    AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术.AJAX是一种进行页面局部异步刷新的技术,局 ...

  7. python基础——列表生成式

    python基础——列表生成式 列表生成式即List Comprehensions,是Python内置的非常简单却强大的可以用来创建list的生成式. 举个例子,要生成list [1, 2, 3, 4 ...

  8. QML入门教程

    QML是Qt推出的Qt Quick技术的一部分,是一种新增的简便易学的语言.QML是一种陈述性语言,用来描述一个程序的用户界面:无论是什么样子,以及它如何表现.在QML,一个用户界面被指定为具有属性的 ...

  9. Android中make命令

    转自:http://blog.sina.com.cn/s/blog_abc7e49a01011y0n.html 1.make -jXX  XX表示数字,这个命令将编译Android系统并生成镜像,XX ...

  10. Feed系统架构资料收集

    完全用nosql轻松打造千万级数据量的微博系统 微博feed系统的push和pull模式和时间分区拉模式架构探讨 关于如何构建一个微博型广播 关于如何构建一个微博型广播2 用 mongodb 储存多态 ...