后缀数组(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)
真是一个三倍经验好题啊. 我们来观察这个题目,首先如果直接整体计算,怕是不太好计算. 首先,我们可以将每个子串都看成一个后缀的的前缀.那我们就可以考虑一个一个后缀来计算了. 为了方便起见,我们选择按照 ...
随机推荐
- iphone开发笔记
1.uiimage图片拉伸 - (void)stretchBackgroundImage { //UIImage *originalImage = [[self backgroundImageForS ...
- linux 命令——5 rm(转)
昨天学习了创建文件和目录的命令mkdir ,今天学习一下linux中删除文件和目录的命令: rm命令.rm是常用的命令,该命令的功能为删除一个目录中的一个或多个文件或目录,它也可以将某个目录及其下的所 ...
- C#Json数据交互
问题:写项目时,难免会遇到前台和后台要进行数据交换,往前台传一个对象或一个对象集,往后台传一个对象,一个对象集.怎么传,你当然不能直接去传递一个对象或对象集,我们可以利用JSON数据相互之间传值. J ...
- c语言中--typeof--关键字用法
C语言中 typeof 关键字是用来定义变量数据类型的.在linux内核源代码中广泛使用. 下面是Linux内核源代码中一个关于typeof实例: #define min(x, y) ({ \ typ ...
- 通过rsync+inotify实现数据实时备份
rsync的优点与不足 与传统的cp,scp,tar,备份方式相比,rsync具有安全性高备份迅速支持增量备份的优点,可以满足对实时性要求不高的需求,例如定期备份文件服务器数据到远端服务器,但是,当数 ...
- linux几种文件传输方式
本文记录linux系统中文件传输的多种方式,留作备忘.linux中文件传输的方式有ftp,scp,rsync,rz,sz等,但各个工具的功能又有所区别: FTP : FTP是文件服务器,可实现文件的上 ...
- Visual Studio 2017 初次体验
在初次体验中遇到以下问题以及技巧 1. 在出现红色波浪线时为出现错误语法,将鼠标移动到相应位置可以获得相关错误信息 2.在编写代码过程中,行号上出现的小黄灯可以有提示信息 3.List 与 Array ...
- 如何查看连接到手机热点的ip地址
因为最近玩树莓派,需要手机做热点,然后用树莓派连接到这个热点上,苦于不知道树莓派被分配了什么样的ip地址,经过一番探索,我发现了两种办法, 安装一个 android terminal( 安卓命令行), ...
- 用jq给img添加error事件
<img src="xxxx.jpg" alt="" /> <script> $(document).ready(function(){ ...
- Android Studio 3.0 安装注意点
在安装Android studio 3.0+ 时候,会遇到默认不带Android SDK 的问题. 在启动Android studio 后,会提示让选择SDK目录,选择下载目录,对应的去下载 那么问题 ...