BZOJ[3238][Ahoi2013]差异 后缀数组+单调栈

33 篇文章 0 订阅
3 篇文章 0 订阅

传送门ber~

题目大意:求 1i<jnlen(Suffixi)+len(Suffixj)2LCP(Suffixi,Suffixj) ∑ 1 ≤ i < j ≤ n l e n ( S u f f i x i ) + l e n ( S u f f i x j ) − 2 ∗ L C P ( S u f f i x i , S u f f i x j )

len(Suffixi)+len(Suffixj) l e n ( S u f f i x i ) + l e n ( S u f f i x j ) 可以被提出来
剩下的就是要求 1i<jnLCP(Suffixi,Suffixj) ∑ 1 ≤ i < j ≤ n L C P ( S u f f i x i , S u f f i x j )
因为 LCP(Suffixi,Suffixj) L C P ( S u f f i x i , S u f f i x j ) 等价于 Min{Heighti...j} M i n { H e i g h t i . . . j }
单调栈维护即可

代码如下:

#include<algorithm>
#include<cstring>
#include<cstdio>
#define N 500050
using namespace std;
char str[N];
long long ans;
int n,m,top;
int SA[N],las[N],rk[N],buck[N],height[N],l[N],r[N];
inline bool judge(int x,int y,int k){
    return las[x]==las[y] && las[x+k]==las[y+k];
}
inline void Radix_Sort(){
    for(int i=1;i<=m;i++) buck[i]=0;
    for(int i=1;i<=n;i++) buck[rk[las[i]]]++;
    for(int i=1;i<=m;i++) buck[i]+=buck[i-1];
    for(int i=n;i>=1;i--) SA[buck[rk[las[i]]]--]=las[i];
}
inline void Get_SA(){
    n=strlen(str+1);
    for(int i=1;i<=n;i++){
        las[i]=i;rk[i]=str[i];
    }
    m=127;Radix_Sort();m=0;
    for(int i=1;m<n;i<<=1,top=0){
        for(int j=n-i+1;j<=n;j++) las[++top]=j;
        for(int j=1;j<=n;j++) if(SA[j]>i) las[++top]=SA[j]-i;
        Radix_Sort();m=0;
        for(int j=1;j<=n;j++) las[j]=rk[j];
        for(int j=1;j<=n;j++) rk[SA[j]]=judge(SA[j],SA[j-1],i)?m:++m;
    }
    for(int i=1,j=0;i<=n;i++,j=max(j-1,0)){
        while(str[i+j]==str[SA[rk[i]-1]+j]) j++;
        height[rk[i]]=j;
    }
}
struct sta{
    int x,id;
}s[N];
int main(){
    scanf("%s",str+1);
    Get_SA();
    top=0;
    for(int i=1;i<=n;i++){
        while(top && height[i]<s[top].x)
            r[s[top--].id]=i;
        s[++top].x=height[i];
        s[top].id=i;
    }
    while(top) r[s[top--].id]=n+1;
    for(int i=n;i;i--){
        while(top && height[i]<=s[top].x)
            l[s[top--].id]=i;
        s[++top].x=height[i];
        s[top].id=i;
    }
    while(top) r[s[top--].id]=0;
    ans=1ll*(n+1)*n*(n-1)/2;
    for(int i=1;i<=n;i++) ans=ans-2ll*height[i]*(i-l[i])*(r[i]-i);
    printf("%lld",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值