[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 ...
随机推荐
- 用cocos2d-html5做的消除类游戏《英雄爱消除》(3)——游戏主界面
游戏主界面,同时也是主程序,包括sprite的生成加入以及游戏状态的控制. 下面同样贴下源码再讲解; /** * Power by html5中文网(html5china.com) * author: ...
- Java多线程系列 JUC锁07 ConditionObject分析
ConditionObject ConditionObject是AQS中的内部类,提供了条件锁的同步实现,实现了Condition接口,并且实现了其中的await(),signal(),signalA ...
- <再看TCP/IP第一卷>TCP/IP协议族中的最压轴戏----TCP协议及细节
题外话:刚刚过去的半个月实在是忙得我喘不过来气,虽然手里还压着几个项目得在期末考试之前做完,但是想想还是更新一下随笔,稍微换个心情.另外小吐槽一下那些在博客园里原封不动抄书当随笔的人,唉真是....算 ...
- Monkey for Mac 环境配置
Monkey for Mac环境配置步骤 java环境配置, 直接去官网找对应jdk就可以了 Android AdtBundle环境配置 1) 下载地址: http://www.jianshu.co ...
- js里对php存贮的cookie进行读取和删除
/* 读取cookie */ function getCookie(name){ var arr,reg=new RegExp("(^| )"+name+"=([^;]* ...
- Kafka- Kafka架构功能
Kafka是一个高吞吐量的分布式消息系统,一个分布式的发布-订阅消息系统.Kafka是一种快速,可拓展的,设计内在就是分布式的,分区的可复制的提交日志服务. Apache Kafka与传统消息系统相比 ...
- (转)edm注意事项
格式编码 1.页面宽度请设定在600到800px以内,长度1024px以内. 2.HTML编码请使用utf-8. 3.HTML代码在15KB以内.(各个邮箱的收件标准不一样,如果超出15KB您的邮件很 ...
- Hibernate学习---第十二节:Hibernate之锁机制&乐观锁实现
1.悲观锁 它指的是对数据被外界修改保持保守态度,因些,在整个数据处理过程中,将数据牌锁定状态.悲观锁的实现,往往依靠数据库提供的锁机制(也只有数据库层的锁机制才能保证数据访问的排他性,否则,即使在本 ...
- ES索引瘦身 压缩——_source _all 均disable filed store为no,引入第三方DB存储原始数据,去掉pos倒排和doc_values,强制定期merge segments,将所有fileds合并为一个field big string
原始数据:835MB ES 设置了_source _all disabled 且设置了仅仅存docs倒排Wed Feb 22 11:58:27 CST 2017Before size:1 /home/ ...
- Post提交和Get提交的区别
表单提交中get和post的区别 1. get: 把表单内各个字段均显示在URL中. post:把表单内各个字段和内容放在html的header内一起传递给action所指的url,用户看不到. 2. ...