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;
}

猜你喜欢

转载自blog.csdn.net/chm_wt/article/details/81839242
今日推荐