[spoj694&spoj705]New Distinct Substrings(后缀数组)
题意:求字符串中不同子串的个数。
解题关键:每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数。
1、总数减去height数组的和即可。
注意这里height中为什么不需要进行组合计数,因为,每一个height的左端点已经确定,所以只需变动右端点,总共$height[i]$种情况。
2、如果所有的后缀按照 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)。
类似于dp的过程
法一:
- #include <cstdlib>
- #include <cstring>
- #include <cstdio>
- #include <algorithm>
- #include<iostream>
- #include<cmath>
- #define inf 0x3f3f3f3f
- typedef long long ll;
- using namespace std;
- const int N=;
- int wa[N],wb[N],wv[N],wc[N];
- bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
- void make_sa(int *r,int *sa,int n,int m){
- int i,j,p,*x=wa,*y=wb;
- for(i=;i<m;i++) wc[i]=;
- for(i=;i<n;i++) wc[x[i]=r[i]]++;
- for(i=;i<m;i++) wc[i]+=wc[i-];
- for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
- for(j=,p=;p<n;j*=,m=p){
- for(p=,i=n-j;i<n;i++) y[p++]=i;
- for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
- for(i=;i<n;i++) wv[i]=x[y[i]];
- for(i=;i<m;i++) wc[i]=;
- for(i=;i<n;i++) wc[wv[i]]++;
- for(i=;i<m;i++) wc[i]+=wc[i-];
- for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
- for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- }
- return;
- }
- int rank1[N],height[N],sa[N];
- void make_height(int *r,int *sa,int n){
- int i,j,k=;
- for(i=;i<=n;i++) rank1[sa[i]]=i;
- for(i=;i<n;height[rank1[i++]]=k)
- for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
- return;
- }
- int n,k,r[N];
- int main(){
- int t;
- ios::sync_with_stdio();
- cin>>t;
- while(t--){
- string s;
- cin>>s;
- for(int i=;i<s.size();i++) r[i]=(int)s[i];
- r[s.size()]=;
- n=s.size();
- make_sa(r,sa,n+,);
- make_height(r,sa,n);
- ll sum=s.size()*(s.size()+)/;
- for(int i=;i<=n;i++){
- sum-=height[i];
- }
- cout<<sum<<"\n";
- }
- return ;
- }
法二:
- #include <cstdlib>
- #include <cstring>
- #include <cstdio>
- #include <algorithm>
- #include<iostream>
- #include<cmath>
- #define inf 0x3f3f3f3f
- typedef long long ll;
- using namespace std;
- const int N=;
- int wa[N],wb[N],wv[N],wc[N];
- bool cmp(int *r,int a,int b,int l){return r[a]==r[b]&&r[a+l]==r[b+l];}
- void make_sa(int *r,int *sa,int n,int m){
- int i,j,p,*x=wa,*y=wb;
- for(i=;i<m;i++) wc[i]=;
- for(i=;i<n;i++) wc[x[i]=r[i]]++;
- for(i=;i<m;i++) wc[i]+=wc[i-];
- for(i=n-;i>=;i--) sa[--wc[x[i]]]=i;
- for(j=,p=;p<n;j*=,m=p){
- for(p=,i=n-j;i<n;i++) y[p++]=i;
- for(i=;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j;
- for(i=;i<n;i++) wv[i]=x[y[i]];
- for(i=;i<m;i++) wc[i]=;
- for(i=;i<n;i++) wc[wv[i]]++;
- for(i=;i<m;i++) wc[i]+=wc[i-];
- for(i=n-;i>=;i--) sa[--wc[wv[i]]]=y[i];
- for(swap(x,y),p=,x[sa[]]=,i=;i<n;i++) x[sa[i]]=cmp(y,sa[i-],sa[i],j)?p-:p++;
- }
- return;
- }
- int rank1[N],height[N],sa[N];
- void make_height(int *r,int *sa,int n){
- int i,j,k=;
- for(i=;i<=n;i++) rank1[sa[i]]=i;
- for(i=;i<n;height[rank1[i++]]=k)
- for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
- return;
- }
- int n,k,r[N];
- int main(){
- int t;
- ios::sync_with_stdio();
- cin>>t;
- while(t--){
- string s;
- cin>>s;
- for(int i=;i<s.size();i++) r[i]=(int)s[i];
- r[s.size()]=;
- n=s.size();
- make_sa(r,sa,n+,);
- make_height(r,sa,n);
- int sum=;
- for(int i=;i<=n;i++){
- sum+=n-sa[i]-height[i];
- }
- cout<<sum<<"\n";
- }
- return ;
- }
另:整理下DC3模板(r和sa
- #include<cstdlib>
- #include<cstring>
- #include<cstdio>
- #include<algorithm>
- #include<iostream>
- #include<cmath>
- #define inf 0x3f3f3f3f
- typedef long long ll;
- using namespace std;
- const int N=;
- #define F(x) ((x)/3+((x)%3==1?0:tb))
- #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2)
- int wa[N],wb[N],wv[N],ws1[N];
- int c0(int *r,int a,int b){ return r[a]==r[b]&&r[a+]==r[b+]&&r[a+]==r[b+]; }
- int c12(int k,int *r,int a,int b){
- if(k==) return r[a]<r[b]||r[a]==r[b]&&c12(,r,a+,b+);
- else return r[a]<r[b]||r[a]==r[b]&&wv[a+]<wv[b+];
- }
- void sort(int *r,int *a,int *b,int n,int m){
- int i;
- for(i=;i<n;i++) wv[i]=r[a[i]];
- for(i=;i<m;i++) ws1[i]=;
- for(i=;i<n;i++) ws1[wv[i]]++;
- for(i=;i<m;i++) ws1[i]+=ws1[i-];
- for(i=n-;i>=;i--) b[--ws1[wv[i]]]=a[i];
- return;
- }
- void dc3(int *r,int *sa,int n,int m){
- int i,j,*rn=r+n,*san=sa+n,ta=,tb=(n+)/,tbc=,p;
- r[n]=r[n+]=;
- for(i=;i<n;i++) if(i%!=) wa[tbc++]=i;
- sort(r+,wa,wb,tbc,m);
- sort(r+,wb,wa,tbc,m);
- sort(r,wa,wb,tbc,m);
- for(p=,rn[F(wb[])]=,i=;i<tbc;i++)
- rn[F(wb[i])]=c0(r,wb[i-],wb[i])?p-:p++;
- if(p<tbc) dc3(rn,san,tbc,p);
- else for(i=;i<tbc;i++) san[rn[i]]=i;
- for(i=;i<tbc;i++) if(san[i]<tb) wb[ta++]=san[i]*;
- if(n%==) wb[ta++]=n-;
- sort(r,wb,wa,ta,m);
- for(i=;i<tbc;i++) wv[wb[i]=G(san[i])]=i;
- for(i=,j=,p=;i<ta && j<tbc;p++)
- sa[p]=c12(wb[j]%,r,wa[i],wb[j])?wa[i++]:wb[j++];
- for(;i<ta;p++) sa[p]=wa[i++];
- for(;j<tbc;p++) sa[p]=wb[j++];
- return;
- }
- int rank1[N],height[N],sa[*N];
- void make_height(int *r,int *sa,int n){
- int i,j,k=;
- for(i=;i<=n;i++) rank1[sa[i]]=i;
- for(i=;i<n;height[rank1[i++]]=k)
- for(k?k--:,j=sa[rank1[i]-];r[i+k]==r[j+k];k++);
- return;
- }
- int n,k,r[*N];
- int main(){
- int t;
- ios::sync_with_stdio();
- cin>>t;
- while(t--){
- string s;
- cin>>s;
- for(int i=;i<s.size();i++) r[i]=(int)s[i];
- r[s.size()]=;
- n=s.size();
- dc3(r,sa,n+,);
- make_height(r,sa,n);
- int sum=;
- for(int i=;i<=n;i++){
- sum+=n-sa[i]-height[i];
- }
- cout<<sum<<"\n";
- }
- return ;
- }
必须开到3倍大小)
[spoj694&spoj705]New Distinct Substrings(后缀数组)的更多相关文章
- SPOJ - SUBST1 New Distinct Substrings —— 后缀数组 单个字符串的子串个数
题目链接:https://vjudge.net/problem/SPOJ-SUBST1 SUBST1 - New Distinct Substrings #suffix-array-8 Given a ...
- SPOJ - DISUBSTR Distinct Substrings (后缀数组)
Given a string, we need to find the total number of its distinct substrings. Input T- number of test ...
- 【SPOJ – SUBST1】New Distinct Substrings 后缀数组
New Distinct Substrings 题意 给出T个字符串,问每个字符串有多少个不同的子串. 思路 字符串所有子串,可以看做由所有后缀的前缀组成. 按照后缀排序,遍历后缀,每次新增的前缀就是 ...
- SPOJ DISUBSTR Distinct Substrings 后缀数组
题意:统计母串中包含多少不同的子串 然后这是09年论文<后缀数组——处理字符串的有力工具>中有介绍 公式如下: 原理就是加上新的,减去重的,这题是因为打多校才补的,只能说我是个垃圾 #in ...
- SPOJ 694 || 705 Distinct Substrings ( 后缀数组 && 不同子串的个数 )
题意 : 对于给出的串,输出其不同长度的子串的种类数 分析 : 有一个事实就是每一个子串必定是某一个后缀的前缀,换句话说就是每一个后缀的的每一个前缀都代表着一个子串,那么如何在这么多子串or后缀的前缀 ...
- spoj Distinct Substrings 后缀数组
给定一个字符串,求不相同的子串的个数. 假如给字符串“ABA";排列的子串可能: A B A AB BA ABA 共3*(3+1)/2=6种; 后缀数组表示时: A ABA BA 对于A和 ...
- spoj 694. Distinct Substrings 后缀数组求不同子串的个数
题目链接:http://www.spoj.com/problems/DISUBSTR/ 思路: 每个子串一定是某个后缀的前缀,那么原问题等价于求所有后缀之间的不相同的前缀的个数.如果所有的后缀按照su ...
- SPOJ_705_New Distinct Substrings_后缀数组
SPOJ_705_New Distinct Substrings_后缀数组 题意: 给定一个字符串,求该字符串含有的本质不同的子串数量. 后缀数组的一个小应用. 考虑每个后缀的贡献,如果不要求本质不同 ...
- Cogs 1709. [SPOJ705]不同的子串 后缀数组
题目:http://cojs.tk/cogs/problem/problem.php?pid=1709 1709. [SPOJ705]不同的子串 ★★ 输入文件:subst1.in 输出文件: ...
随机推荐
- asm 与 cglib(整理的)
参考博客地址 http://www.oseye.net/user/kevin/blog/304#top http://www.blogjava.net/vanadies10/archive/2011/ ...
- EF6&EFCore 注册/使用实体类的正确姿势
首先回顾下EF中常规使用流程 1.新建实体类以及实体配置(data annotation或fluent api) [Table("Users")] public class Use ...
- 转载 -- iOS开发之JSON格式数据的生成与解析
本文将从四个方面对IOS开发中JSON格式数据的生成与解析进行讲解: 一.JSON是什么? 二.我们为什么要用JSON格式的数据? 三.如何生成JSON格式的数据? 四.如何解析JSON格式的数据? ...
- C#抓取网面上的html内容(JS动态生成的无法抓取)
抓取内容的代码: /// </summary> /// <param name="url">路径URL</param> /// <para ...
- windows下MySQL 5.7+ 解压缩版安装配置方法(转,写的很简单精辟 赞)
方法来自伟大的互联网. 1.去官网下载.zip格式的MySQL Server的压缩包,根据需要选择x86或x64版.注意:下载是需要注册账户并登录的. 2.解压缩至你想要的位置. 3.复制解压目录下m ...
- JS之字符串与JSON转换
JS之字符串转换JSON 1.eval 古老的方式 function strToJson(str){ var json = eval('(' + str + ')'); return json; ...
- global 全局变量的用法
说明:i 和foo()都为全局变量,i 是在模块文件顶层注册的,所以为全局变量,他能够在函数内部进行引用而不需要再特意声明是全局变量,且foo()函数也是全局变量 1.当没有局部变量时,print(i ...
- main方法的参数
敲例子的时候无意中把主方法的参数给落下了,当时没有发现,保存之后就去编译,运行了,通常情况下编译没有错误那胜利就在掌握之中了,没想到这次我竟然在"不一般"的行列中,编译无误,运行出 ...
- iPad actionsjeet
在iphone和ipad上使用UIActionShee控件t的效果会不一样,在苹果的官方文档中有相关说明: 在ipad上使用UIActionSheet控件改控件不再从底部弹出,而是从屏幕中间弹出与UI ...
- SQL 数据类型 numeric varchar char
Numeric(10,2) 指字段是数字型,长度为10 小数为两位的 简要描述一下SQL中的五种数据类型:字符型,文本型,数值型,逻辑型和日期型 字符型 VARCHAR VS CHAR VARCHAR ...