题目见此

题解:首先所有后缀都在最后一个np节点,然后他们都是从1号点出发沿一些字符边到达这个点的,所以下文称1号点为根节点,我们思考一下什么时候会产生lcp,显然是当他们从根节点开始一直跳相同节点的时候,所以思路就是先找出每个节点被几个后缀经过,这显然把边反转倒着找就可以了,然后他会被出现次数sz个串经过。

出现次数等于parent树子树中np类节点的个数,这跑个dfs就好了,一个相同前缀产生的贡献是sz*(sz-1)/2

然后思考一个点可能代表多个子串,但是他们的出现次数都是相同的,所以单个点的贡献为上面的单个贡献再乘上一个有几个子串

子串的个数为parent树父亲节点的最大长度减去该节点的最大长度

这样子在从根开始dfs,如果经过某个点只有一个后缀经过,就说明lcp结束了,就不用再搜该点了。

上面就求出了lcp的和

至于前面那个式子,只需要打个表找个规律发现是(n-1)*n*(n+1)/2就可以了

虽然常数大点但是还是后缀自动机复杂度的

但其实不用这么复杂,只要翻过来就可以建出原串后缀树,lcp就是后缀树的两个节点的lca,跑个树形dp就可以了。

代码因为没用链式前向星存边所以不开o2会t,但还是贴一下吧

#include<bits/stdc++.h>
#define N 1000010
using namespace std; int n;
int gg=; struct SAM
{
struct point
{
int son[],fa,len,mx;
}t[N]; int cnt=,last=;
int f[N],sz[N];
bool vis[N];
vector<int> g[N],e[N];
long long lcp=0ll; void add(int c)
{
int p=last;
int np=++cnt;
t[np].len=t[p].len+;
sz[np]=;
while(p&&(!t[p].son[c]))
{
t[p].son[c]=np;
p=t[p].fa;
}
if(!p) t[np].fa=;
else
{
int q=t[p].son[c],nq;
if(t[p].len+==t[q].len)
{
t[np].fa=q;
}
else
{
nq=++cnt;
t[nq]=t[q];
t[nq].len=t[p].len+;
t[q].fa=t[np].fa=nq;
while(p&&(t[p].son[c]==q))
{
t[p].son[c]=nq;
p=t[p].fa;
}
}
}
last=np;
} void dfs(int now)
{
t[now].mx=t[now].len-t[t[now].fa].len;
for(int i=;i<;i++)
{
if(t[now].son[i]) e[t[now].son[i]].push_back(now);
}
for(int i=;i<g[now].size();i++)
{
dfs(g[now][i]);
sz[now]+=sz[g[now][i]];
}
} void dfs1(int now)
{
vis[now]=;
for(int i=;i<e[now].size();i++)
{
f[e[now][i]]++;
if(!vis[e[now][i]])
{
dfs1(e[now][i]);
}
}
} void dfs3(int now)
{
vis[now]=;
if(f[now]) lcp+=t[now].mx*(1ll*sz[now]*(sz[now]-)/);
for(int i=;i<;i++)
{
if(f[t[now].son[i]]&&sz[t[now].son[i]]>&&(!vis[t[now].son[i]]))
{
dfs3(t[now].son[i]);
}
}
} void solve()
{
for(int i=;i<=cnt;i++) g[t[i].fa].push_back(i);
dfs();
sz[]=;
memset(vis,,sizeof(vis));
dfs1(last);
memset(vis,,sizeof(vis));
dfs3();
long long len=1ll*n*(n-)*(n+)/;
printf("%lld\n",len-*lcp);
} }sam; char s[]; int main()
{
scanf("%s",s);
n=strlen(s);
for(int i=;i<n;i++)
{
sam.add(s[i]-'a');
}
sam.solve();
}

洛谷P4248 [AHOI2013]差异(后缀自动机求lcp之和)的更多相关文章

  1. [洛谷P4248][AHOI2013]差异

    题目大意:给一个长度为$n$的字符串,求: $$\sum\limits_{1\leqslant i<j\leqslant n}|suf_i|+|suf_j|-2\times lcp(suf_i, ...

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

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

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

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

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

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

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

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

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

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

  7. 洛谷4248 AHOI2013差异 (后缀数组SA+单调栈)

    补博客! 首先我们观察题目中给的那个求\(ans\)的方法,其实前两项没什么用处,直接\(for\)一遍就求得了 for (int i=1;i<=n;i++) ans=ans+i*(n-1); ...

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

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

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

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

随机推荐

  1. IPMS 元件实作

    一.改用zg框架的jsp 1.引入表头和表尾jsp <%@ include file="../../jsp/menuHeader.jsp"%> <%@ inclu ...

  2. css position定位详解

    position:static 默认方式: position:relative 相对定位,相对于原有位置进行移动,并且保留它在文件流中的占位: position:absolute 绝对定位,相对于最近 ...

  3. x86汇编知识点汇总

    目录: 1.进制转换 2.原码.反码.补码 3.寄存器 4.存储器的段结构 5.堆栈 6.传送类指令 7.算术运算类指令(不含乘除) 8.位操作类指令 9.标志位操作指令 10.标识符.常量与变量 1 ...

  4. JAVA序列化和反序列化 对象<=>IO流 对象<=>字节数组

    http://developer.51cto.com/art/201202/317181.htm http://blog.csdn.net/earbao/article/details/4691440 ...

  5. 单词拆分 I · Word Break

    [抄题]: 给出一个字符串s和一个词典,判断字符串s是否可以被空格切分成一个或多个出现在字典中的单词. s = "lintcode" dict = ["lint" ...

  6. xcode - 显示安装过的低版本模拟器

    1. 更改版本

  7. Spring框架的事务管理之基于AspectJ的注解方式(重点掌握,最简单的方式)

    1. 步骤一:恢复转账的开发环境(具体开发环境实现见:https://www.cnblogs.com/wyhluckdog/p/10137283.html)2. 步骤二:applicationCont ...

  8. Spring基于AspectJ的AOP的开发之AOP的相关术语

    1. Joinpoint(连接点) -- 所谓连接点是指那些被拦截到的点.在spring中,这些点指的是方法,因为spring只支持方法类型的连接点(任何一个方法都可以称为连接点) 2. Pointc ...

  9. xmlhttp

    File an issue about the selected textFile an issue about the selected text XMLHttpRequest Living Sta ...

  10. cout<<endl 本质探索

    C++中,有一种对象叫操控器(manipulators),专门用来操控stream的对象,在C++标准中,预定义好几种操控器,常见的有: flush 刷新output缓冲区,将内容写入输出设备 end ...