不同子串个数

Posted tian-luo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不同子串个数相关的知识,希望对你有一定的参考价值。

不同子串个数
时间限制1.00 s
内存限制125.00 MB

题目背景

因为NOI被虐傻了,蒟蒻的YJQ准备来学习一下字符串,于是它碰到了这样一道题:

题目描述

给你一个长为N的字符串,求不同的子串的个数

我们定义两个子串不同,当且仅当有这两个子串长度不一样 或者长度一样且有任意一位不一样。

子串的定义:原字符串中连续的一段字符组成的字符串

输入格式

第一行一个整数N

接下来一行N个字符表示给出的字符串

输出格式

一行一个整数,表示不一样的子串个数

输入输出样例

输入 #1
5
aabaa
输出 #1
11
输入 #2
3
aba
输出 #2
5

说明/提示

请使用64位整数来进行输出

(具体来说,C++和C选手请使用long long 类型,pascal选手请使用Int64)

由于输入文件过大,请使用 高效的读入方法(具体的,c++和c选手请不要使用cin,pascal选手不需要管)

对于30%的数据,N\le 1000N1000

对于100%的数据,N\le 10^5N105


参考博客:https://www.luogu.org/blog/Elaborate/solution-p2408

技术图片
#include<bits/stdc++.h>
const int N = 4e5+50;
using namespace std;

struct SuffixArray

    int sa[N],rank[N],height[N],cnt[N],a1[N],a2[N],n,m,*x,*y;
    void sort()
    
        for(int i=0; i<m; i++) cnt[i]=0;
        for(int i=0; i<n; i++) cnt[x[i]]++;
        for(int i=1; i<m; i++) cnt[i]+=cnt[i-1];
        for(int i=n-1; i>=0; i--) sa[--cnt[x[y[i]]]]=y[i];
    
    void build(char *s,int c_size)
    
        n=strlen(s);
        m=c_size;
        x=a1;
        y=a2;
        for(int i=0; i<n; i++) x[i]=s[i],y[i]=i;
        x[n]=y[n]=-1;
        sort();
        for(int k=1; k<=n; k<<=1)
        
            int p=0;
            for(int i=n-k; i<n; i++) y[p++]=i;
            for(int i=0; i<n; i++) if(sa[i]>=k) y[p++]=sa[i]-k;
            sort();
            p=0;
            std::swap(x,y);
            x[sa[0]]=0;
            for(int i=1; i<n; i++)
            
                if(y[sa[i]]!=y[sa[i-1]]||y[sa[i]+k]!=y[sa[i-1]+k]) p++;
                x[sa[i]]=p;
            
            if(p+1>=n) break;
            m=p+1;
        
        for(int i=0; i<n; i++) rank[sa[i]]=i;
        height[0]=0;
        int k=0;
        for(int i=0; i<n; i++)
        
            if(k) k--;
            if(rank[i]==0) continue;
            int j=sa[rank[i]-1];
            while(i+k<n&&j+k<n&&s[i+k]==s[j+k]) k++;
            height[rank[i]]=k;
        
    
 SA;


int main()

    char s[N]= 0;
    long long len;
    scanf("%d %s",&len,s);

    SA.build(s,256);

    long long ans=len*(len+1)/2;
        
    for(int i=1; i<len; i++)
    
        ans-=SA.height[i];
    

    printf("%lld\n",ans);//
    return 0;
View Code

 

以上是关于不同子串个数的主要内容,如果未能解决你的问题,请参考以下文章

「Luogu P2408」不同子串个数

P2408 不同子串个数

[TyvjP1515] 子串统计 [luoguP2408] 不同子串个数(后缀数组)

[spoj DISUBSTR]后缀数组统计不同子串个数

SPOJ 694 不同子串个数

SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )