1. 程式人生 > >[BZOJ3238][Ahoi2013]差異

[BZOJ3238][Ahoi2013]差異

Time Limit: 20 Sec
Memory Limit: 512 MB

Description

在這裡插入圖片描述

Input

一行,一個字串S

Output

一行,一個整數,表示所求值

Sample Input

cacao

Sample Output

54

HINT

2 < = N

< = 500000 2<=N<=500000 , S由小寫英文字母組成

題解:
學了一發字尾陣列,
s a [

i ] = j sa[i] = j 表示為按照從小到大排名為i的字尾 是以j(下標)開頭的字尾
r k [
i ] = j rk[i] = j
表示為按照從小到大排名 以i為下標開始的字尾 排名為 j j
h [ i ] h[i] 表示 l c p ( i , i 1 ) lcp(i,i-1)
用單調棧維護 l c p ( 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;
}