您的位置:首页 > 其它

[AHOI2013]差异

2018-02-26 17:35 127 查看

题目描述

给定一个长度为 $n$ 的字符串 $S$ ,令 $T_i$ 表示它从第 $i$ 个字符开始的后缀。求

$\displaystyle \sum_{1\leqslant i<j\leqslant n}\text{len}(T_i)+\text{len}(T_j)-2\times\text{lcp}(T_i,T_j)$

其中,$\text{len}(a)$ 表示字符串 $a$ 的长度,$\text{lcp}(a,b)$ 表示字符串 $a$ 和字符串 $b$ 的最长公共前缀。

输入输出格式

输入格式:

一行,一个字符串 $S$ 。

输出格式:

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

输入输出样例

输入样例#1:
复制
cacao


输出样例#1: 复制
54


说明

对于 100% 的数据,保证 $2\leqslant n\leqslant 500000$ ,且均为小写字母。

先用后缀数组求出height数组(h数组)

那么两个点i,j的LCP就是$min{h[k] | i+1<=k<=j}$

考虑每个h[i]的贡献

假设L[i]表示L[i]~i-1的h值都大于等于h[i]

而R[i]表示i+1~R[i]的h值大于h[i](之所以不是大于等于是为了避免相同的h带来重复答案)

$ans-=2*lcp(T_i,T_j)$

$ans-=2*(i-L[i]+1)*(R[i]-i+1)*h[i]$

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long lol;
int n,m,c[600001];
int x[600001],y[600001],SA[600001],s[600001],rank[600001],st[600001],top;
lol L[600001],R[600001];
lol h[600001],ans,sum;
char ch[600001];
void radix_sort()
{int i;
for (i=0;i<m;i++)
c[i]=0;
for (i=0;i<n;i++)
c[x[y[i]]]++;
for (i=1;i<m;i++)
c[i]+=c[i-1];
for (i=n-1;i>=0;i--)
SA[--c[x[y[i]]]]=y[i];
}
void build()
{int i,j,k,p;
for (i=0;i<n;i++)
y[i]=i,x[i]=s[i];
m=500000;
radix_sort();
for (k=1;k<=n;k*=2)
{
p=0;
for (i=n-k;i<n;i++)
y[p++]=i;
for (i=0;i<n;i++)
if (SA[i]>=k) y[p++]=SA[i]-k;
radix_sort();
p=1;swap(x,y);
x[SA[0]]=0;
for (i=1;i<n;i++)
x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&((SA[i]+k<n?y[SA[i]+k]:-1)==(SA[i-1]+k<n?y[SA[i-1]+k]:-1)))?p-1:p++;
if (p>n) break;
m=p;
}
for (i=0;i<n;i++)
rank[SA[i]]=i;
int len=0;
for (i=0;i<n;i++)
if(rank[i]>0)
{
if (len) len--;
j=SA[rank[i]-1];
while (i+len<n&&j+len<n&&(s[i+len]==s[j+len])) len++;
h[rank[i]]=len;
}
}
int main()
{int i,j;
cin>>ch;
n=strlen(ch);
for (i=0;i<n;i++)
{
s[i]=ch[i]-'a'+1;
}
build();
for (i=0;i<n;i++)
{
while (top&&h[i]<=h[st[top]]) top--;
if (top==0) L[i]=0;
else L[i]=st[top]+1;
st[++top]=i;
}
top=0;
for (i=n-1;i>=0;i--)
{
while (top&&h[i]<h[st[top]]) top--;
if (top==0) R[i]=n-1;
else R[i]=st[top]-1;
st[++top]=i;
}
for (i=1;i<=n;i++)
ans+=(lol)i*(lol)(n-1);
for (i=0;i<n;i++)
{
ans-=2ll*((lol)i-(lol)L[i]+1ll)*((lol)R[i]-(lol)i+1ll)*(lol)h[i];
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: