[BZOJ3238][Ahoi2013]差異
阿新 • • 發佈:2018-12-02
Time Limit: 20 Sec
Memory Limit: 512 MB
Description
Input
一行,一個字串S
Output
一行,一個整數,表示所求值
Sample Input
cacao
Sample Output
54
HINT
, S由小寫英文字母組成
題解:
學了一發字尾陣列,
表示為按照從小到大排名為i的字尾 是以j(下標)開頭的字尾
表示為按照從小到大排名 以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;
}