[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 输出文件: ...
随机推荐
- ASP.NET动态网站制作(8)-- JS(3)
前言:JS的第三节课,这节课主要讲函数.对象及方法. 内容: 1.九九乘法表例子: HTML代码: <!DOCTYPE html> <html xmlns="http:// ...
- Linux 开启端口,操作防火墙
命令行方式: 添加10002端口方法 1.vi etc/sysconfig/iptables 2. 开放端口命令:-A INPUT -p tcp -m state --state NEW -m ...
- 【BZOJ1336】[Balkan2002]Alien最小圆覆盖 随机增量法
[BZOJ1336][Balkan2002]Alien最小圆覆盖 Description 给出N个点,让你画一个最小的包含所有点的圆. Input 先给出点的个数N,2<=N<=10000 ...
- cmake policy
1 cmake policy是什么? cmake policy可以理解为cmake的语法标准,也就是说,它规定了cmake在解析CMakeLists.txt文件时的行为. 2 cmake policy ...
- iOS应用上架报错解决
ERROR ITMS-90087: "Unsupported Architectures. The executable for LiveStorage.app/Frameworks/Spe ...
- Software-defined networking
Software-defined networking administrators to programmatically initialize, control, change, and mana ...
- 【题解】cycle
[题解]cycle 题目描述 给定一个无向图,求一个环,使得环内边权\(\div\)环内点数最大. 数据范围 \(n \le 5000\) \(m\le 10000\) \(Solution\) 考虑 ...
- 我的Android进阶之旅------>Android如何去除GridView的按下或点击选中后的背景效果
今天用GridView做了一个界面,自己自定好了一个组件,并且设置好了点击和不点击组件时候的效果,但是运行的时候发现在我定义好的背景下面还有一层不知道哪儿来的背景,严重影响了我自定义的组件的效果. 后 ...
- java参数传递------真心是值传递
未完待续 不同意的请尽管去深入看一下. 对象是引用传递没错,参数传递是值传递.
- C++ 构造函数+析构函数
3-2 构造函数的调用 Time Limit: 1000MS Memory limit: 65536K 题目描述 通过本题目的练习可以掌握构造函数和析构函数的调用: 创建类A:类中仅包含构造函数和析构 ...