Evanyou Blog 彩带

  题目传送门

不同字串个数

题目背景

因为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%的数据, $Nle 1000$

对于100%的数据, $Nle 10^5$


  分析:

  后缀数组入门好题,刚学,特地来水一波。

  首先做这道题需要会后缀数组,并深入理解$height[]$数组的含义,然后需要知道一个非常重要的性质。下面这一段话引用自罗穗骞的论文:

  每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。如果所有的后缀按照 suffix(sa[1]), suffix(sa[2]),suffix(sa[3]), …… ,suffix(sa[n])的顺序计算,不难发现,对于每一次新加进来的后缀 suffix(sa[k]),它将产生 n-sa[k]+1 个新的前缀。但是其中有height[k]个是和前面的字符串的前缀是相同的。所以 suffix(sa[k])将“贡献”出 n-sa[k]+1- height[k]个不同的子串。累加后便是原问题的答案。这个做法的时间复杂度为 O(n)。

  知道这些这道题就可以轻松A过了。

  Code:

//It is made by HolseLee on 13th Aug 2018
//Luogu.org P2408
#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N=1e5+7;
int n,m,height[N],sa[N],rk[N],y[N],c[N];
ll ans;
char s[N];

void Sort()
{
    for(int i=0;i<=m;++i)c[i]=0;
    for(int i=1;i<=n;++i)c[rk[i]]++;
    for(int i=1;i<=m;++i)c[i]+=c[i-1];
    for(int i=n;i>=1;--i)sa[c[rk[y[i]]]--]=y[i];
}

void getsa()
{
    for(int i=1;i<=n;++i)rk[i]=s[i]-'0',y[i]=i;
    Sort();
    for(int k=1,cnt=0;cnt<n;m=cnt,k<<=1){
        cnt=0;
        for(int i=1;i<=k;++i)y[++cnt]=n-k+i;
        for(int i=1;i<=n;++i)if(sa[i]>k)y[++cnt]=sa[i]-k;
        Sort();
        swap(y,rk);
        rk[sa[1]]=cnt=1;
        for(int i=2;i<=n;++i)
        rk[sa[i]]=(y[sa[i]]==y[sa[i-1]]&&y[sa[i]+k]==y[sa[i-1]+k])?cnt:++cnt;
    }
}

void getheight()
{
    int k=0,j;
    for(int i=1;i<=n;++i){
        if(k)k--;
        j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        height[i]=k;
    }
}

int main()
{
    scanf("%d%s",&n,s+1);
    m=75;
    getsa();getheight();
    for(int i=1;i<=n;++i)
    ans+=(n-sa[i]+1-height[i]);
    printf("%lld",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cytus/p/9470616.html