[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 输出文件: ...
随机推荐
- Python 深入剖析SocketServer模块(二)(V2.7.11)
五.Mix-In混合类 昨天介绍了BaseServer和BaseRequestHandler两个基类,它们只用与派生,所以贴了它们派生的子类代码. 今天介绍两个混合类,ForkingMix-In 和 ...
- EasyNVR NVR网页无插件直播在兼容宇视NVR RTSP流媒体时PLAY过程对Scale的兼容
前一段在维护EasyNVR客户的过程中遇到一个问题,在接入宇视NVR的时候,就是明明在vlc中能非常正常播放的视频流,却用EasyRTSPClient RTSP客户端拉流的协议交互过程中,PLAY命令 ...
- 九度OJ 1156:谁是你的潜在朋友 (并查集)
时间限制:1 秒 内存限制:32 兆 特殊判题:否 提交:5802 解决:2593 题目描述: "臭味相投"--这是我们描述朋友时喜欢用的词汇.两个人是朋友通常意味着他们存在着许多 ...
- json字符串转集合或者数组
import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util. ...
- 2017-2018-1 20179209《Linux内核原理与分析》第七周作业
一.实验 1.1task_struct数据结构 Linux内核通过一个被称为进程描述符的task_struct结构体来管理进程,这个结构体包含了一个进程所需的所有信息.它定义在linux-3.18.6 ...
- JavaScript 四种显示数据方式
<!doctype html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- 辛星跟您玩转vim第四节之操作文本内容
首先值得一提的是.我的vim教程pdf版本号已经写完了.大家能够去下载,这里是csdn的下载地址:csdn下载,假设左边的下载地址挂掉了,也能够自行在浏览器以下输入例如以下地址进行下载:http:// ...
- centos 7 官网安装 PostgreSQL
https://www.postgresql.org/download/linux/redhat/
- axios无法在ie9,10,11环境下运行的问题解决
npm install es6-promise --save-dev import promise from 'es6-promise'; promise.polyfill();
- JS工具函数汇总
备注:http://phpjs.org/ 这个站点把PHP常用的方法用js实现了,推荐一下 1.从数组中随机获取几个不重复项 //从一个给定的数组arr中,随机返回num个不重复项 function ...