[tyvj1860]后缀数组
题目链接:http://www.tyvj.cn/p/1860
解题关键:模板题。贴一个代码详解
http://www.cnblogs.com/staginner/archive/2012/02/02/2335600.html
注意:一个字符串中的所有子串都必然是它的后缀的前缀
da算法,必须保证字符串中每个字符的映射>=1
注意点:sa从0~n-1,rank1数组和height数组从1-n
height[1]恒为0
#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
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){//最大值小于m
int i,j,p,*x=wa,*y=wb;//x,y是指针
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;//y是第二关键词的sa
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++;//x是rank数组,1 1 2 2 2 3 这种
}
return;
}
int rank1[N],height[N],sa[N];//注意sa和rank的对应关系,sa的数值从0开始,rank的数值从1开始
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;
}
//sa是名次所在位置,rank是位置所在名次
int r[N<<];
int main() {
ios::sync_with_stdio();
int n=;
string s;
cin>>s;
for(int i=;i<s.size();i++) r[n++]=s[i]-'a'+; r[n]=;
make_sa(r,sa,n+,);
make_height(r,sa,n);
for(int i=;i<=n;i++) cout<<sa[i]+<<" ";cout<<"\n";//这里的1是逻辑上的首位
for(int i=;i<=n;i++) cout<<height[i]<<" ";cout<<"\n";
}
下面这种调用方式更无脑一些
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include<iostream>
#include<cstdlib>
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){//m是至多有多少个字符,up的意思
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];//输出都是从1开始存的,rank从0开始,最后需要+1,读入从下标0
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;
}
//sa是名次所在位置,rank是位置所在名次
int r[N];
int main() {
ios::sync_with_stdio();
cin.tie();
cout.tie();
string s;
cin>>s;
for(int i=;i<s.size();i++) r[i]=(int)s[i];
int t=(int)s.size();
r[t]=;
make_sa(r, sa,t+,);//注意+1,因为补0的原因
make_height(r, sa, t);
for(int i=;i<=t;i++) cout<<sa[i]+<<" ";
cout<<"\n";
for(int i=;i<=t;i++) cout<<height[i]<<" ";
cout<<"\n";
return ;
}
后缀数组练习
poj2774 最长公共子串问题,将两个字符串接在一起解决。height数组就代表lcp(最长公共前缀)
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include<iostream>
#include<cstdlib>
using namespace std;
const int N=;
int wa[N],wb[N],wv[N],wc[N],n,m;
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 r[N<<];
int main() {
ios::sync_with_stdio();
string s,t;
cin>>s>>t;
int n=;
for(int i=;i<s.size();i++) r[n++]=s[i]-'a'+; r[n++]=;int sl=n;
for(int i=;i<t.size();i++) r[n++]=t[i]-'a'+; r[n]=;
make_sa(r, sa, n+, );
make_height(r, sa, n);
int ans=;
for(int i=;i<n;i++){
if((sa[i]<sl)!=(sa[i+]<sl)){
ans=max(ans,height[i+]);
}
}
cout<<ans<<"\n";
return ;
}
[tyvj1860]后缀数组的更多相关文章
- 【tyvj1860】后缀数组
描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])< ...
- 后缀数组的倍增算法(Prefix Doubling)
后缀数组的倍增算法(Prefix Doubling) 文本内容除特殊注明外,均在知识共享署名-非商业性使用-相同方式共享 3.0协议下提供,附加条款亦可能应用. 最近在自学习BWT算法(Burrows ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]
1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1383 Solved: 582[Submit][St ...
- POJ3693 Maximum repetition substring [后缀数组 ST表]
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9458 Acc ...
- POJ1743 Musical Theme [后缀数组]
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 27539 Accepted: 9290 De ...
- 后缀数组(suffix array)详解
写在前面 在字符串处理当中,后缀树和后缀数组都是非常有力的工具. 其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料. 其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现, ...
- 【UOJ #35】后缀排序 后缀数组模板
http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...
- 【BZOJ-2119】股市的预测 后缀数组
2119: 股市的预测 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 334 Solved: 154[Submit][Status][Discuss ...
随机推荐
- GIT笔记:GITHUB教程【官方自译版】
GIT笔记:将项目发布到GITHUB GITHUB是什么 GitHub是版本控制和协作的代码托管平台.它可以让你和其他人在任何地方一起工作. 1.创建一个新的仓库 存储库通常用于组织单个项目.存储库可 ...
- Hadoop2.x + eclipse 插件配置
http://blog.csdn.net/u012874209/article/details/52105304 搭建集群那些就不用说了,主要有几个关键的地方需要注意(自己的Hadoop版本是2.5. ...
- LeetCode:二叉树的前、中、后序遍历
描述: ------------------------------------------------------- 前序遍历: Given a binary tree, return the pr ...
- 微信小程序消息模板
wxml: <form bindsubmit='sendSms' report-submit='true' id='fo'> <button form-type='submit'&g ...
- 【leetcode刷题笔记】Longest Substring Without Repeating Characters
Given a string, find the length of the longest substring without repeating characters. For example, ...
- 纯CSS3垂直动画菜单
在线演示 本地下载
- static{}块的作用
本文转载自: https://www.cnblogs.com/caolaoshi/p/7824748.html static{}块,会且仅会在类被加载时执行一次,多用于定义静态变量或执行静态方法. 什 ...
- php数据结构课程---4、栈(是什么)
php数据结构课程---4.栈(是什么) 一.总结 一句话总结: 栈(stack),它是一种运算受限的线性表.其限制是仅允许在表的一端进行插入和删除运算. 1.栈的链表实现? 定义node,设置属性d ...
- pow,sqrt使用时需注意
使用时注意类型,可见两者皆不可以用int 1.pow 函数声明: double pow (double base , double exponent); float pow (float base , ...
- MyBaties--Mapper configuration
method one: <!-- Using classpath relative resources --> <mappers> <mapper resource=&q ...