[bzoj3238] [Ahoi2013] 差异
Posted lindalee
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[bzoj3238] [Ahoi2013] 差异相关的知识,希望对你有一定的参考价值。
Description
给定一个长度为 (n) 的字符串 (S),令 (Ti) 表示它从第 (i) 个字符开始的后缀。求
(sumlimits_{1 leq i <j leq n} len(Ti)+len(Tj)-2 imes lcp(Ti,Tj))
其中,(len(a)) 表示字符串 (a) 的长度,(lcp(a,b)) 表示字符串 (a) 和字符串 (b) 的最长公共前缀。
Input
一行,一个字符串 (S)。
Output
一行,一个整数,表示所求值。
Sample Input
cacao
Sample Output
54
HINT
对于 (100%) 的数据,保证 (2 leq n leq 500000),且均为小写字母。
想法
化简一下要求的那个式子
[
egin{equation*}
egin{aligned}
&sumlimits_{1 leq i <j leq n} len(Ti)+len(Tj)-2 imes lcp(Ti,Tj) =&frac{n(n+1)(n-1)}{2} -2 imes sumlimits_{1 leq i <j leq n} lcp(Ti,Tj)
end{aligned}
end{equation*}
]
不妨设 (x= sumlimits_{1 leq i <j leq n} lcp(Ti,Tj)) ,我们要求的就是它
建出后缀自动机,对于其中每个节点,预处理出它可以到的结束节点的个数 (size) ,这个点对 (x) 的贡献就是 (frac{size(size-1)}{2})
代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 500005;
typedef long long ll;
struct node{
int len,size;
node *ch[26],*pa;
}pool[N*2],*root,*last;
int cnt;
void insert(int c){
node *p=last,*cur=&pool[++cnt];
cur->len=p->len+1;
for(;p && !p->ch[c];p=p->pa) p->ch[c]=cur;
if(!p) cur->pa=root;
else{
node *q=p->ch[c],*nq;
if(q->len==p->len+1) cur->pa=q;
else{
nq=&pool[++cnt];
nq->len=p->len+1;
for(int i=0;i<26;i++) nq->ch[i]=q->ch[i];
nq->pa=q->pa;
q->pa=cur->pa=nq;
for(;p && p->ch[c]==q;p=p->pa) p->ch[c]=nq;
}
}
last=cur;
}
char s[N];
int n;
ll ans,del[N*2];
int vis[N*2];
void Get_size(node *p){
if(vis[p-pool]) {
ans-=del[p-pool];
return;
}
ll pre=ans;
for(int i=0;i<26;i++){
if(!p->ch[i]) continue;
Get_size(p->ch[i]);
p->size+=p->ch[i]->size;
}
if(p->size>=2) ans-=(ll)p->size*(p->size-1);
del[p-pool]=pre-ans; vis[p-pool]=1;
}
int main()
{
scanf("%s",s);
n=strlen(s);
root=&pool[++cnt];
last=root;
for(int i=0;i<n;i++) insert(s[i]-'a');
node *tmp=last;
for(;tmp!=root;tmp=tmp->pa) tmp->size=1;
ans=(ll)n*(n+1)/2*(n-1);
Get_size(root);
printf("%lld
",ans+(ll)n*(n-1));
return 0;
}
以上是关于[bzoj3238] [Ahoi2013] 差异的主要内容,如果未能解决你的问题,请参考以下文章
bzoj 3238: [Ahoi2013]差异 -- 后缀数组