1. 程式人生 > >1166不相同的子串的個數——字尾陣列

1166不相同的子串的個數——字尾陣列

題目描述
給定一個字串,求不相同的子串的個數。

輸入
輸入資料第一行為一個數字 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; }