您的位置:首页 > 其它

不同子串

2016-02-02 10:57 295 查看

  题目描述:给定一个有小写英文字母构成的字符串T,求其不同子串个数

  数据范围及限制:一个串,长度不超过100000

  输入样例1:

    ababa

  输出样例1:

    9

  输入样例2:

    ebvylfeicorjhpovljmgqawckptcqfuynhvnqwokvowxjgvjhztxmgzwkgvuvhsilrslnzcvmconbabwrpfniknqsimyutwstzzc

  输出样例2:

    4968

  输入样例3:

    riokzisztaydqovqjcdnojfykqjfstevddxtxbtwgzlmwqnhijuemkxaaqmjqscdpnzgseezaexluxdmdkoijafpecganbycwsjs

  输出样例3: 

    4999757677

  题解:

    因为每个子串都是某个后缀的前缀,所以想到用后缀数组,首先要知道后缀数组中height[i]的含义,height[i]不仅指排名第i的和排名第i-1的(后缀)的最长相同前缀,还指排名第i的和排名1~i-1的最长相同前缀,可以举几个例子试试。

    知道了这个性质,那么每一个后缀中只能由它得到的前缀的个数就是n-sa[i]-height[i],n-sa[i]得到这个后缀的长度(我是从0开始的),height[i]个前缀在排名1~i-1的后缀中已经得到,所以要减去,不计入答案。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
typedef long long LL;
const LL maxn=200000;
LL r[maxn],sa[maxn],wa[maxn],wb[maxn],wv[maxn],Ws[maxn];
LL cmp(LL *r,LL a,LL b,LL l){
return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(LL *r,LL *sa,LL n,LL m){
LL i,j,p,*x=wa,*y=wb,*t;
for(i=0;i<m;i++) Ws[i]=0;
for(i=0;i<n;i++) Ws[x[i]=r[i]]++;
for(i=1;i<m;i++) Ws[i]+=Ws[i-1];
for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i;

for(j=1,p=1;p<n;j*=2,m=p){
for(p=0,i=n-j;i<n;i++) y[p++]=i;
for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;

for(i=0;i<n;i++) wv[i]=x[y[i]];
for(i=0;i<m;i++) Ws[i]=0;
for(i=0;i<n;i++) Ws[wv[i]]++;
for(i=0;i<m;i++) Ws[i]+=Ws[i-1];
for(i=n-1;i>=0;i--) sa[--Ws[wv[i]]]=y[i];

for(t=x,x=y,y=t,x[sa[0]]=0,p=1,i=1;i<n;i++)
x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
}
}
LL rank[maxn],height[maxn];
void calheight(LL *r,LL *sa,LL n){
LL i,j,k=0;
for(i=0;i<n;i++) rank[sa[i]]=i;
for(i=0;i<n;height[rank[i++]]=k)
for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++);
return ;
}
char s[maxn];
LL num[maxn],len,ans;
int main(){
freopen("distinct.in","r",stdin);
freopen("distinct.out","w",stdout);
scanf("%s",s); len=strlen(s);
for(LL i=0;i<len;i++) num[i]=s[i]-'a'+2;
da(num,sa,len,30);
calheight(num,sa,len); height[0]=0;
for(LL i=0;i<len;i++){
LL k=len-sa[i];
ans+=k-height[i];
}
printf("%lld",ans);
return 0;
}

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: