[BZOJ3238][Ahoi2013]差异

Time Limit: 20 Sec
Memory Limit: 512 MB

Description

在这里插入图片描述

Input

一行,一个字符串S

Output

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

Sample Input

cacao

Sample Output

54

HINT

2 &lt; = N &lt; = 500000 2&lt;=N&lt;=500000 2<=N<=500000 , S由小写英文字母组成

题解:
学了一发后缀数组,
s a [ i ] = j sa[i] = j sa[i]=j表示为按照从小到大排名为i的后缀 是以j(下标)开头的后缀
r k [ i ] = j rk[i] = j rk[i]=j表示为按照从小到大排名 以i为下标开始的后缀 排名为 j j j
h [ i ] h[i] h[i]表示 l c p ( i , i − 1 ) lcp(i,i-1) lcp(i,i1)
用单调栈维护 l c p ( L , R ) = h [ i ] lcp(L,R)=h[i] lcp(L,R)=h[i]重复计数就取左不取右。

#include<bits/stdc++.h>
#define LiangJiaJun main
#define ll long long
#define pa pair<int,int>
#define INF 1000000000
using namespace std;
ll ans;
int l,k,p,q,a[500004],v[500004];
int sa[2][500004],rk[2][500004],h[500004];
char str[500004];
int st[500004],L[500004],R[500004],top;
void work(int *sa,int *rk,int *SA,int *RK){
     for(int i=1;i<=l;i++)v[rk[sa[i]]]=i;
     for(int i=l;i;i--){
         if(sa[i]>k){
            SA[v[rk[sa[i]-k]]--]=sa[i]-k;
         }
     }
     for(int i=l-k+1;i<=l;i++)SA[v[rk[i]]--]=i;
     for(int i=1;i<=l;i++){
         RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i-1]]!=rk[SA[i]]||rk[SA[i-1]+k]!=rk[SA[i]+k]);
     }
     return ;
}
void presa(){
     for(int i=1;i<=l;i++)v[a[i]]++;
     for(int i=1;i<=30;i++)v[i]+=v[i-1];
     for(int i=1;i<=l;i++)sa[p][v[a[i]]--]=i;
     for(int i=1;i<=l;i++){
         rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
     }
     for(k=1;k<l;k<<=1,swap(p,q))work(sa[p],rk[p],sa[q],rk[q]);
     for(int k=0,i=1;i<=l;i++){
         int j=sa[p][rk[p][i]-1];
         while(str[j+k]==str[i+k])k++;
         h[rk[p][i]]=k;
         if(k>0)k--;
     }
}
void solve(){
     h[0]=-INF;
     for(int i=1;i<=l;i++)ans+=1LL*i*(l-1);
     top=0;st[0]=0;
     for(int i=1;i<=l;i++){
         while(h[i]<=h[st[top]])top--;
         if(st[top]==0)L[i]=1;
         else L[i]=st[top]+1;
         st[++top]=i;
     }
     h[l+1]=-INF;top=0;st[0]=l+1;
     for(int i=l;i;i--){
         while(h[i]<h[st[top]])top--;
         if(st[top]==l+1)R[i]=l;
         else R[i]=st[top]-1;
         st[++top]=i;
     }
     for(int i=1;i<=l;i++){
         ans-=2LL*(i-L[i]+1)*(R[i]-i+1)*h[i];
     }
}
int w33ha(){
    memset(v,0,sizeof(v));
    memset(h,0,sizeof(h));
    memset(sa,0,sizeof(sa));
    memset(rk,0,sizeof(rk));
    ans=0;p=0;q=1;
    l=strlen(str+1);
    for(int i=1;i<=l;i++)a[i]=str[i]-'a'+1;
    presa();
    solve();
    printf("%lld\n",ans);
    return 0;
}
int LiangJiaJun(){
    while(scanf("%s",str+1)!=EOF)w33ha();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值