后缀数组(SA)学习记录
一只只会后缀自动机却不会后缀数组的弱鸡做了一下HDU - 1403,结果SAM被卡内存了,然后学习了一下SA。
以下两道题都是求LCS,区别在于字符串长度。
参考blog:https://www.cnblogs.com/victorique/p/8480093.html
HDU - 1403
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rank Rank
using namespace std;
const int MAXN = 2e5+;
char str[MAXN];
int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN];
//rank[i] 第i个后缀的排名, SA[i] 排名为i的后缀的位置, Height[i] 排名为i的后缀与排名为(i-1)的后缀的LCP
//sum[i] 基数排序辅助数组, 存储小于i的元素有多少个, tp[i] rank的辅助数组(按第二关键字排序的结果),与SA意义一样
bool cmp(int *f, int x, int y, int w){return f[x] == f[y] && f[x + w] == f[y + w];} void get_SA(char *s, int n, int m)
{
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[i] = s[i]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[i]]] = i;
for(int len = ; len <= n; len <<= )
{
int p = ;
for(int i = n - len; i < n; i++) tp[p++] = i;
for(int i = ; i < n; i++)
if(SA[i] >= len)
tp[p++] = SA[i] - len;
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[tp[i]]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[tp[i]]]] = tp[i];
swap(rank, tp);
p = ;
rank[SA[]] = ;
for(int i = ; i < n; i++)
rank[SA[i]] = cmp(tp, SA[i - ], SA[i], len) ? p - : p++;
if(p >= n) break;
m = p;
}
int k = ;
n--;
for(int i = ; i <= n; i++) rank[SA[i]] = i;
for(int i = ; i < n; i++)
{
if(k) k--;
int j = SA[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
}
int main()
{
while(~scanf("%s", str))
{
int len = strlen(str);
str[len] = '';
scanf("%s", str + len + );
int n = strlen(str);
str[n] = ; //末尾添加一个0
get_SA(str, n + , 'z' + );
int sol = ;
for(int i = ; i < n; i++)
{
if(SA[i] > len && SA[i - ] < len) sol = max(sol, height[i]);
if(SA[i] < len && SA[i - ] > len) sol = max(sol, height[i]);
}
printf("%d\n", sol);
}
return ;
}
SPOJ - LCS
SA版本:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rank Rank
using namespace std;
const int MAXN = 5e5+;
char str[MAXN];
int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN];
//rank[i] 第i个后缀的排名, SA[i] 排名为i的后缀的位置, Height[i] 排名为i的后缀与排名为(i-1)的后缀的LCP
//sum[i] 基数排序辅助数组, 存储小于i的元素有多少个, tp[i] rank的辅助数组(按第二关键字排序的结果),与SA意义一样
bool cmp(int *f, int x, int y, int w){return f[x] == f[y] && f[x + w] == f[y + w];} void get_SA(char *s, int n, int m)
{
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[i] = s[i]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[i]]] = i;
for(int len = ; len <= n; len <<= )
{
int p = ;
for(int i = n - len; i < n; i++) tp[p++] = i;
for(int i = ; i < n; i++)
if(SA[i] >= len)
tp[p++] = SA[i] - len;
for(int i = ; i < m; i++) sum[i] = ;
for(int i = ; i < n; i++) sum[rank[tp[i]]]++;
for(int i = ; i < m; i++) sum[i] += sum[i - ];
for(int i = n - ; i >= ; i--) SA[--sum[rank[tp[i]]]] = tp[i];
swap(rank, tp);
p = ;
rank[SA[]] = ;
for(int i = ; i < n; i++)
rank[SA[i]] = cmp(tp, SA[i - ], SA[i], len) ? p - : p++;
if(p >= n) break;
m = p;
}
int k = ;
n--;
for(int i = ; i <= n; i++) rank[SA[i]] = i;
for(int i = ; i < n; i++)
{
if(k) k--;
int j = SA[rank[i] - ];
while(s[i + k] == s[j + k]) k++;
height[rank[i]] = k;
}
}
int main()
{
while(~scanf("%s", str))
{
int len = strlen(str);
str[len] = '';
scanf("%s", str + len + );
int n = strlen(str);
str[n] = ; //末尾添加一个0
get_SA(str, n + , 'z' + );
int sol = ;
for(int i = ; i < n; i++)
{
if(SA[i] > len && SA[i - ] < len) sol = max(sol, height[i]);
if(SA[i] < len && SA[i - ] > len) sol = max(sol, height[i]);
}
printf("%d\n", sol);
}
return ;
}
SAM版本:
#include<bits/stdc++.h>
using namespace std;
const int kind=;
const int maxn=;
struct state
{
state *Next[kind],*link;
int len;
state()
{
link=;
len=;
memset(Next,,sizeof(Next));
}
};
int sz;
state st[maxn*+];
inline state* newnode(int len = )
{
memset(st[sz].Next,,sizeof(st[sz].Next));
st[sz].link=;
st[sz].len=len;
return &st[sz++];
}
state *root,*last;
void extend(int w)
{
state* p=last;
state* cur=newnode(p->len+);
while(p&&p->Next[w]==)
{
p->Next[w]=cur;
p=p->link;
}
if(p)
{
state* q=p->Next[w];
if(p->len+==q->len)
cur->link=q;
else
{
state* clone=newnode(p->len+);
memcpy(clone->Next,q->Next,sizeof(q->Next));
clone->link=q->link;
q->link=clone;
cur->link=clone;
while(p&&p->Next[w]==q)
{
p->Next[w]=clone;
p=p->link;
}
}
}
else cur->link=root;
last=cur;
}
string keyword;
int main()
{
ios::sync_with_stdio(false);
while(cin>>keyword)
{
sz=;
int ans=;
root=newnode();
last=root;
for(int i=;i<keyword.size();i++)
extend(keyword[i]-'a');
cin>>keyword;
state *p=root;
int tmp=;
for(int i=;i<keyword.size();i++)
{
if(p->Next[keyword[i]-'a'])
{
tmp++;
p=p->Next[keyword[i]-'a'];
}
else
{ while(p&&!p->Next[keyword[i]-'a'])
p=p->link;
if(!p)
p=root;
if(p->Next[keyword[i]-'a'])
{
tmp=p->len+;
p=p->Next[keyword[i]-'a'];
}
else
tmp=;
}
ans=max(ans,tmp);
}
cout<<ans<<endl;
}
return ;
}
后缀数组(SA)学习记录的更多相关文章
- 后缀数组SA学习笔记
什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...
- 后缀数组SA入门(史上最晦涩难懂的讲解)
参考资料:victorique的博客(有一点锅无伤大雅,记得看评论区),$wzz$ 课件(快去$ftp$%%%),$oi-wiki$以及某个人的帮助(万分感谢!) 首先还是要说一句:我不知道为什么我这 ...
- 后缀数组(SA)总结
后缀数组(SA)总结 这个东西鸽了好久了,今天补一下 概念 后缀数组\(SA\)是什么东西? 它是记录一个字符串每个后缀的字典序的数组 \(sa[i]\):表示排名为\(i\)的后缀是哪一个. \(r ...
- bzoj3796(后缀数组)(SA四连)
bzoj3796Mushroom追妹纸 题目描述 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从 ...
- [笔记]后缀数组SA
参考资料这次是真抄的: 1.后缀数组详解 2.后缀数组-学习笔记 3.后缀数组--处理字符串的有力工具 定义 \(SA\)排名为\(i\)的后缀的位置 \(rk\)位置为\(i\)的后缀的排名 \(t ...
- 浅谈后缀数组SA
这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的. 给你们分享了那么多,容我自私一回吧~ 参考资料:这位dalao的blog 一.关于求Suffix ...
- 【字符串】后缀数组SA
后缀数组 概念 实际上就是将一个字符串的所有后缀按照字典序排序 得到了两个数组 \(sa[i]\) 和 \(rk[i]\),其中 \(sa[i]\) 表示排名为 i 的后缀,\(rk[i]\) 表示后 ...
- 洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记
题目链接 //输出ht见UOJ.35 #include<cstdio> #include<cstring> #include<algorithm> const in ...
- 后缀数组SA
复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...
- 洛谷2408不同字串个数/SPOJ 694/705 (后缀数组SA)
真是一个三倍经验好题啊. 我们来观察这个题目,首先如果直接整体计算,怕是不太好计算. 首先,我们可以将每个子串都看成一个后缀的的前缀.那我们就可以考虑一个一个后缀来计算了. 为了方便起见,我们选择按照 ...
随机推荐
- .net reflector 的缺陷
.net reflector是一个反编译DLL的工具,在安装后如果电脑上有VS也会同时安装到VS里面,但是他是收费的,虽然反编译的效果很好,但是运行VS2013时(或许其他版本也有这样的问题)如果项目 ...
- bzoj4622 [NOI 2003] 智破连环阵
Description B国在耗资百亿元之后终于研究出了新式武器——连环阵(Zenith Protected Linked Hybrid Zone).传说中,连环阵是一种永不停滞的自发性智能武器.但经 ...
- 【CF1000C】Covered Points Count(离散化+差分)
点此看题面 大致题意: 给出\(n\)条线段,分别求有多少点被覆盖\(1\)次.\(2\)次...\(n\)次. 正常的算法 好吧,这道题目确实有个很简单的贪心做法(只可惜我做的时候没有想到,结果想了 ...
- Flutter /bin/sh: /packages/flutter_tools/bin/xcode_backend.sh: No such file or directory
自己写项目中遇到的一个问题, 可以出来是路径找不到,应该是FLUTTER_ROOT这个全局变量没有取到值的原因 1.检查xcode_backend.sh 是否真的存在 2.网上说的:Target -& ...
- fopen, fdopen, freopen - 打开流
SYNOPSIS (总览) #include <stdio.h> FILE *fopen(const char *path, const char *mode); FILE *fdopen ...
- Count Numbers(矩阵快速幂)
Count Numbers 时间限制: 8 Sec 内存限制: 128 MB提交: 43 解决: 19[提交] [状态] [讨论版] [命题人:admin] 题目描述 Now Alice want ...
- MooseFS 3.0 集群环境部署过程
1 准备好6台虚拟机:(centos7) Master server: 192.168.242.135 Cgi server: 192.168.242.135 meta ...
- Bootstrap 轮播(Carousel)插件
轮播插件是一种灵活的响应式的向站点添加滑块的方式.除此之外,内容也是非常灵活的.可是图像,内嵌框架,视频或者其它您想的放置任何内容的类型. 下面是一个简单的幻灯片,使用轮播(carousel)插件显示 ...
- C#的接口基础教程之六 接口转换
C#中不仅支持.Net 平台,而且支持COM平台.为了支持 COM和.Net,C# 包含一种称为属性的独特语言特性.一个属性实际上就是一个 C# 类,它通过修饰源代码来提供元信息.属性使 C# 能够支 ...
- WP Mail SMTP插件解决Contact Form 7表单提交失败问题
WP Mail SMTP插件解决Contact Form 7表单提交失败问题 WP Mail SMTP是一款非常优秀的解决WordPress主机因为不支持或者是禁用了mail()函数,导致无法实现在线 ...