您的位置:首页 > 其它

【bzoj3238】【AHOI2013】【差异】【后缀数组+单调栈】

2016-06-15 16:06 453 查看

Description



Input

一行,一个字符串S

Output

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

Sample Input

cacao

Sample Output

54

HINT

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

          把式子拆开之后可以发现就是所有后缀长度的n-1倍减去任两个后缀的lcp的长度的两倍.

          第一部分直接算即可,第二部分可以用后缀数组.

          求出height数组之后对于height[i]找出他前面第一个小于等于它的位置和后面第一个小于它的位置.

          这之间的i前面的和i后面的任意两个后缀的lcp长度都是height[i];

          扫一遍统计一下即可.

代码:

 

#include<iostream>
#include<cstdio>
#include<cstring>
#define N 500010
using namespace std;
int n,sa
,s
,t1
,t2
,rank
,c
,h
,after
,pre
,top,st
;
long long ans;
char ch
;
bool cmp(int *y,int p,int q,int k){
int a=(p+k)>=n?-1:y[p+k];
int b=(q+k)>=n?-1:y[q+k];
return a==b&&y[p]==y[q];
}
void build_sa(int m){
int *x=t1,*y=t2;
for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[i]=s[i]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[i]]]=i;
for (int k=1;k<=n;k<<=1){
int p=0;
for (int i=n-k;i<n;i++) y[p++]=i;
for (int i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k;
for (int i=0;i<m;i++) c[i]=0;
for (int i=0;i<n;i++) c[x[y[i]]]++;
for (int i=1;i<m;i++) c[i]+=c[i-1];
for (int i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i];
swap(x,y);
p=1;x[sa[0]]=0;
for (int i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i],sa[i-1],k)?p-1:p++;
if (p>=n) break;
m=p;
}
}
void geth(){
int k(0);
for (int i=0;i<n;i++) rank[sa[i]]=i;
for (int i=0;i<n;i++){
if (!rank[i]) continue;
if (k) k--;int j=sa[rank[i]-1];
while (s[j+k]==s[i+k]) k++;
h[rank[i]]=k;
}
//for (int i=0;i<n;i++) cout<<h[i]<<' ';
//cout<<endl;
}
int main(){
scanf("%s",ch);n=strlen(ch);
for (int i=0;i<n;i++) s[i]=ch[i]-'a'+1;
build_sa(27);geth();
for (int i=1;i<=n;i++) ans+=i;
ans=ans*(long long)(n-1);
top=0;pre[1]=0;st[++top]=1;
for (int i=2;i<=n-1;i++){
while (top&&h[st[top]]>h[i]) top--;
pre[i]=st[top];
st[++top]=i;
}
top=0;after[n-1]=n;st[++top]=n-1;st[0]=n;
for (int i=n-1;i>=1;i--){
while (top&&h[st[top]]>=h[i]) top--;
after[i]=st[top];
st[++top]=i;
}
// for (int i=1;i<n;i++) cout<<pre[i]<<' '<<after[i]<<endl;
for (int i=1;i<n;i++)
ans=ans-(long long)(after[i]-i)*(i-pre[i])*h[i]*2;
cout<<ans<<endl;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: