一只只会后缀自动机却不会后缀数组的弱鸡做了一下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)学习记录的更多相关文章

  1. 后缀数组SA学习笔记

    什么是后缀数组 后缀数组\(sa[i]\)表示字符串中字典序排名为\(i\)的后缀位置 \(rk[i]\)表示字符串中第\(i\)个后缀的字典序排名 举个例子: ababa a b a b a rk: ...

  2. 后缀数组SA入门(史上最晦涩难懂的讲解)

    参考资料:victorique的博客(有一点锅无伤大雅,记得看评论区),$wzz$ 课件(快去$ftp$%%%),$oi-wiki$以及某个人的帮助(万分感谢!) 首先还是要说一句:我不知道为什么我这 ...

  3. 后缀数组(SA)总结

    后缀数组(SA)总结 这个东西鸽了好久了,今天补一下 概念 后缀数组\(SA\)是什么东西? 它是记录一个字符串每个后缀的字典序的数组 \(sa[i]\):表示排名为\(i\)的后缀是哪一个. \(r ...

  4. bzoj3796(后缀数组)(SA四连)

    bzoj3796Mushroom追妹纸 题目描述 Mushroom最近看上了一个漂亮妹纸.他选择一种非常经典的手段来表达自己的心意——写情书.考虑到自己的表达能力,Mushroom决定不手写情书.他从 ...

  5. [笔记]后缀数组SA

    参考资料这次是真抄的: 1.后缀数组详解 2.后缀数组-学习笔记 3.后缀数组--处理字符串的有力工具 定义 \(SA\)排名为\(i\)的后缀的位置 \(rk\)位置为\(i\)的后缀的排名 \(t ...

  6. 浅谈后缀数组SA

    这篇博客不打算讲多么详细,网上关于后缀数组的blog比我讲的好多了,这一篇博客我是为自己加深印象写的. 给你们分享了那么多,容我自私一回吧~ 参考资料:这位dalao的blog 一.关于求Suffix ...

  7. 【字符串】后缀数组SA

    后缀数组 概念 实际上就是将一个字符串的所有后缀按照字典序排序 得到了两个数组 \(sa[i]\) 和 \(rk[i]\),其中 \(sa[i]\) 表示排名为 i 的后缀,\(rk[i]\) 表示后 ...

  8. 洛谷.3809.[模板]后缀排序(后缀数组 倍增) & 学习笔记

    题目链接 //输出ht见UOJ.35 #include<cstdio> #include<cstring> #include<algorithm> const in ...

  9. 后缀数组SA

    复杂度:O(nlogn) 注:从0到n-1 const int maxn=1e5; char s[maxn]; int sa[maxn],Rank[maxn],height[maxn],rmq[max ...

  10. 洛谷2408不同字串个数/SPOJ 694/705 (后缀数组SA)

    真是一个三倍经验好题啊. 我们来观察这个题目,首先如果直接整体计算,怕是不太好计算. 首先,我们可以将每个子串都看成一个后缀的的前缀.那我们就可以考虑一个一个后缀来计算了. 为了方便起见,我们选择按照 ...

随机推荐

  1. 使用adbWireless无线调试Android真机设备[转]

    开发Android的朋友都知道,真机调试需要把手机与PC相连,然后把应用部署到真机上进行安装和调试.长长的USB线显得很麻烦,而且如果需要USB接口与其他设备连接的话显得很不方便.今天介绍一种不通过U ...

  2. sql server2016安装程序图

    今天终于有时间安装SQL Server2016正式版,下载那个安装包都用了一个星期 安装包可以从这里下载: http://www.itellyou.cn/ https://msdn.microsoft ...

  3. 《Ruby on Rails教程》学习笔记

    本文是我在阅读 Ruby on Rails 教程的简体中文版时所做的摘录,以及学习时寻找的补充知识.补充知识主要来自于 Ruby on Rails 實戰聖經. Asset Pipeline 在最新版 ...

  4. Linux 的歷史

    Unix 狹義作業系統提供應用程式及命令直譯器. 作業系統發展初期並不具可攜性. Bell, GE 及 MIT 合作開發的 "Multice" 系統( 相容分時系統 ). 1969 ...

  5. python_31_集合

    # 集合是一个无序的,不重复的数据组合,它的主要作用如下: # 去重,把一个列表变成集合,就自动去重了 # 关系测试,测试两组数据之前的交集.差集.并集等关系 s = set([3, 5, 9, 10 ...

  6. java设计模式——单例模式(二)

     破坏单例模式 上一章节,介绍了单例模式的几种方式,这次来学习一波我们创建的单例模式是否安全,能不能破坏.换句话说,也就是在程序运行中,不止有一个实例. 一. 序列化,反序列化破坏 以饿汉式的单例模式 ...

  7. C#语句对Access中数据更新问题――Update语法错误

    所有字段最好都用[] 括起来: string sqlUpdate = "update UserInfo set [password] = '" + pass + "',[ ...

  8. webpack 4.x 解决 webpack-dev-server工具在webpack构建的项目中使用问题

    webpack-dev-server工具能实现自动打包编译和热更新 首先将webpack-dev-server安装到项目中 npm install webpack-dev-server -D 这时在命 ...

  9. dijkstra算法优先队列

    d[i] 是起点到 I 节点的最短距离 void Dijkstra(int s) { priority_queue<P, vector<P>, greater<P> &g ...

  10. Uva 派 (Pie,NWERC 2006,LA 3635)

    依然是一道二分查找 #include<iostream> #include<cstdio> #include<cmath> using namespace std; ...