p2408 不同子串个数

传送门

分析

首先我们不难求出一共有多少子串

之后我们只需要减掉重复个数即可

于是我们对于每个后缀减去它跟它前一名的最长公共前缀即可

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cctype>
#include<cmath>
#include<cstdlib>
#include<ctime>
#include<queue>
#include<vector>
#include<set>
#include<map>
#include<stack>
using namespace std;
#define int long long
inline int max(int x,int y){return x>y?x:y;}
char s[100100];
int Ans,n,m=128,rk[100100],tp[100100],sa[100100],tax[100100],h[100100];
inline void qsort(){
    for(int i=0;i<=m;i++)tax[i]=0;
    for(int i=1;i<=n;i++)tax[rk[i]]++;
    for(int i=1;i<=m;i++)tax[i]+=tax[i-1];
    for(int i=n;i>0;i--)sa[tax[rk[tp[i]]]--]=tp[i];
}
inline void work(){
    for(int i=1;i<=n;i++)rk[i]=s[i]-'0'+1,tp[i]=i;qsort();
    for(int w=1,p=0;p<n;m=p,w<<=1){
      p=0;for(int i=1;i<=w;i++)tp[++p]=n-w+i;
      for(int i=1;i<=n;i++)if(sa[i]>w)tp[++p]=sa[i]-w;
      qsort();swap(rk,tp);rk[sa[1]]=p=1;
      for(int i=2;i<=n;i++)rk[sa[i]]=(tp[sa[i-1]]==tp[sa[i]]&&tp[sa[i-1]+w]==tp[sa[i]+w])?p:++p;
    }
    for(int i=1;i<=n;++i)rk[sa[i]]=i;h[0]=0;
    for(int i=1;i<=n;++i){
      h[i]=max(h[i-1]-1,0);
      while(i+h[i]<=n&&sa[rk[i]-1]+h[i]<=n&&s[i+h[i]]==s[sa[rk[i]-1]+h[i]])h[i]++;
    }
}
signed main(){
    scanf("%lld",&n);scanf("%s",s+1);work();
    for(int i=1;i<=n;i++)Ans+=(n-sa[i]+1-h[i]);
    cout<<Ans;
    return 0;
}
原文地址:https://www.cnblogs.com/yzxverygood/p/10606046.html