[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 输出文件: ...
随机推荐
- programming review (c++): (1)vector, linked list, stack, queue, map, string, bit manipulation
编程题常用知识点的review. most important: 想好(1)详尽步骤(2)边界特例,再开始写代码. I.vector #include <iostream> //0.头文件 ...
- MySQL CREATE TRIGGER (1)
CREATE TRIGGER语法 CREATE TRIGGER trigger_name trigger_time trigger_event ON tbl_name FOR EACH ROW ...
- NDK以及C语言基础语法(二)
一.字符串类:(属于类类型) -String (在C++中才有) 使用之前必学引入String 类型: 引入String头文件(系统的头文件): #include <string> p ...
- Git 自己的一些工作中的总结
这个网址很重要:https://gitee.com/progit/2-Git-%E5%9F%BA%E7%A1%80.html#2.4-%E6%92%A4%E6%B6%88%E6%93%8D%E4%BD ...
- html学习笔记(2)-字母大小写转换练习
主要应用了text-transform属性值: uppercase:所有单词的字母都大写: lowercase:所有单词的字母都小写: capitalize:每个单词的首字母都大写: none:默认值 ...
- Bloom Filters
http://pages.cs.wisc.edu/~cao/papers/summary-cache/node8.html A Bloom filter is a method for represe ...
- mysql系列之1.mysql基础
非关系型(NOSQL)数据库 键值存储数据库: memcached / redis / memcachedb / Berkeley db 列存储数据库: Cassandra / Hba ...
- pjax + tp5,实现局部无刷新返回数据
文件1:\application\admin\controller\Setting.php 最后一句代码:要fetch原页面 <?php namespace app\admin\controll ...
- 题解 P1387 【最大正方形】
传送门 搞不清楚为什么这一题要DP . . . . . . 思路: \(n\le100\),考虑暴力. 要求一大块区间内都是1,考虑前缀和. 在矩阵中求一个符合条件的子矩阵,考虑\(n^3\)的&qu ...
- 【linux】top更改排序顺序
top更改排序顺序的方式有很多,这里介绍两个比较简单使用的. 1,快捷键: 大写M:根据内存排序,默认从大到小,大写R更改为从小到大排序 大写P:根据CPU使用排序,默认从大到小,大写R更改为从小到大 ...