不同子串
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; }
相关文章推荐
- 处理 WordPress RESTfull API(WP API) 中的用户认证,发送 POST 请求
- shell后台进程id
- Eclipse调试Android工具集锦之三-ADB
- js获取某月的天数以及某天的前一个日期和后一天日期
- 监听UIWebView点击视频播放的事件
- javascript实现瀑布流加载图片原理
- SSD Trim
- 分布式基础通信协议:paxos,totem和gossip
- 去除button点击下去的 灰色阴影效果
- hdu4597 Play Game(DFS)
- selenium(二):小而精
- 如何选择 compileSdkVersion, minSdkVersion 和 targetSdkVersion
- Error:(1, 0) Plugin is too old, please update to a more recent version, or set ANDROID_DAILY_OVERRID
- ubuntu开启root用户ssh远程登录
- Python入门教程
- wcf rest 服务用于安卓和ISO调用2-------文件上传
- 判断UITextField 输入为空 输入全为空格
- 大数据挖掘: FPGrowth初识--进行商品关联规则挖掘
- 代码阅读工具:Source Navigator和Source Insight
- 归并排序的原理及java代码实现