[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 ...
随机推荐
- 小程序获取openid和unionid java实现
官方api:https://developers.weixin.qq.com/miniprogram/dev/api/api-login.html#wxloginobject 参考文章:https:/ ...
- persisted? vs new_record?
https://joe11051105.gitbooks.io/you-need-to-know-about-ruby-on-rails/content/activerecord/persisted_ ...
- UI组件之Label
Use Core Data 接口,链接数据库 Portrait 肖像模式 LandScape(Left, Right) 风景模式 1.程序启动后,从main接口进入, main函数会调用UIAppli ...
- Linux Glibc库严重安全漏洞修复方案通知(腾讯开发者社区)
如何查看当前glibc的版本号? rpm -aq | grep glibc 尊敬的用户: 您好!2015年1月28日, 腾讯云安全情报监测到LinuxGlibc库存在一处严重安全漏洞,可以 ...
- Android_微信_设置
减少 内存的使用 (http://news.ifeng.com/a/20170716/51440541_0.shtml) 1.关闭“附近的人” 打开微信,依次点击[我]—[设置]—[通用]—[功能], ...
- python Tkinter之Button
Button小部件是一个标准的Tkinter的部件,用于实现各种按钮.按钮可以包含文本或图像,您可以调用Python函数或方法用于每个按钮. Tkinter的按钮被按下时,会自动调用该函数或方法. 该 ...
- memset和memcopy用法
void *memset(void *s, int ch, size_t n); 函数解释:将s中前n个字节 (typedef unsigned int size_t)用 ch 替换并返回 s . m ...
- BZOJ 1597 [Usaco2008 Mar]土地购买:斜率优化dp
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1597 题意: 有n块矩形土地,长为a[i],宽为b[i]. FJ想要将这n块土地全部买下来 ...
- 一张图理解is_nll isset empty
isset 判断变量是否已存在,如果变量存在则返回 TRUE,否则返回 FALSE. empty 判断变量是否为空,如果变量是非空 或非零 的值,则 empty() 返回 FALSE.换句话说,&qu ...
- TCP/IP 详解卷一 - TCP CWR、ECE、URG、ACK、PSH、RST、SYN、FIN控制位
from:https://blog.csdn.net/u012243115/article/details/43487461 2015年02月04日 15:56:32 阅读数:1464 TCP 和 U ...