1166不相同的子串的個數——字尾陣列
阿新 • • 發佈:2018-11-09
題目描述
給定一個字串,求不相同的子串的個數。
輸入
輸入資料第一行為一個數字 T,表示資料組數。(T<=10)
接下來的 T 行,每行一個由小寫或大寫字母構成的字串,字串長度不超過 50000。
輸出
對於每組資料,輸出一行一個數字,表示答案。
樣例輸入
4
abbabba
dabddkababa
bacaba
baba
樣例輸出
17
55
17
7
題解
對於每一個字尾 sa[i],他都可以產生 n-sa[i] 個字首, 然後刪去 h[i] 和之前重複的即為答案
字尾陣列部分詳見 https://blog.csdn.net/qq_32461955/article/details/81707008
程式碼
#include<bits/stdc++.h>
#define ll int
#define maxn 50010
using namespace std;
char s[maxn];
ll sa[maxn],tp[maxn],rk[maxn],tax[maxn],n,m=127,hei[maxn],ans,T;
void qsort(){
for(ll i=0;i<=m;i++) tax[i]=0;
for(ll i=1;i<=n;i++) tax[rk[tp[i]]]++;
for(ll i=1;i<=m;i++) tax[i]+=tax[i-1 ];
for(ll i=n;i>=1;i--) sa[tax[rk[tp[i]]]--]=tp[i];}
void suffix(){
for(ll i=1;i<=n;i++) rk[i]=s[i],tp[i]=i;
qsort();
for(ll k=1,p=0;k<=n;k<<=1){
for(ll i=n-k+1;i<=n;i++) tp[++p]=i;
for(ll i=1;i<=n;i++) if(sa[i]>k) tp[++p]=sa[i]-k;
qsort();
swap(rk,tp);
rk[sa[1 ]]=p=1;
for(ll i=2;i<=n;i++) rk[sa[i]]=(tp[sa[i]]==tp[sa[i-1]]&&tp[sa[i]+k]==tp[sa[i-1]+k])?p:++p;
if(p==n) break;
m=p;p=0;}
}
void height(){
for(ll i=1,j=0,k=0;i<=n;i++){
j=sa[rk[i]-1];
if(k) k--;
while(s[j+k]==s[i+k]) k++;
hei[rk[i]]=k;}
}
void work(){
scanf("%s",s+1);
n=strlen(s+1);
suffix();
height();
for(ll i=1;i<=n;i++) ans+=n-sa[i]+1-hei[i];
printf("%lld\n",ans);}
int main(){
cin>>T;
while(T--){
m=127;ans=0;
work();}
return 0;
}