后缀数组

hdu2328(后缀数组 + 二分)

半腔热情 提交于 2019-12-21 11:46:18
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2328 题意: 求 n 个串的字典序最小的最长公共子串 思路: 本题中单个字符串长度不超过 200, 可以暴力枚举一个字符串的所有前缀, 然后用kmp去匹配其他字符串. 我这里是用后缀数组写的. 类似 http://www.cnblogs.com/geloutingyu/p/7450580.html 不过本题是有 n 个字符串, 不能直接暴力判断. 不难想到这里可以直接二分答案长度, 不过 check 函数比较难想到, 具体看代码 代码: 1 #include <iostream> 2 #include <stdio.h> 3 #include <string.h> 4 #define rank Rank 5 using namespace std; 6 7 const int MAXN = 1e6 + 10; 8 int sol; 9 char str[MAXN]; 10 int SA[MAXN], rank[MAXN], height[MAXN], sum[MAXN], tp[MAXN], vis[MAXN], tag[(int)(4e3 + 10)]; 11 12 bool cmp(int *f, int x, int y, int w){ 13 return f[x] == f

[HDU2328]Corporate Identity(后缀数组)

你。 提交于 2019-12-21 11:45:41
传送门 求 n 个串的字典序最小的最长公共子串。 和 2 个串的处理方法差不多。 把 n 个串拼接在一起,中间连上一个没有出现过的字符防止匹配过界。 求出 height 数组后二分公共子串长度给后缀数组分组。 然后 check,每一组中是否所有的字符串都包含。 直接遍历 sa 数组,第一个满足的结果就是字典序最小的。 ——代码 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #define N 900005 5 #define M 4001 6 7 int n, len, m, start; 8 int buc[N], x[N], y[N], sa[N], rank[N], height[N], belong[N]; 9 char s[N], a[M]; 10 bool f[M]; 11 12 inline void build_sa() 13 { 14 int i, k, p; 15 for(i = 0; i < m; i++) buc[i] = 0; 16 for(i = 0; i < len; i++) buc[x[i] = s[i]]++; 17 for(i = 1; i < m; i++) buc[i] += buc[i - 1]; 18 for(i = len - 1; i >= 0; i

【经典数据结构】后缀数组

自作多情 提交于 2019-12-19 07:35:17
   转自:http://www.acmerblog.com/suffix-array-6150.html   在字符串处理当中,后缀树和后缀数组都是非常有力的工具,其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料。其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现,能够实现后缀树的很多功能而时间复杂度也不太逊色,并且,它比后缀树所占用的空间小很多。   后缀树组是一个字符串的所有后缀的排序数组。后缀是指从某个位置 i 开始到整个串末尾结束的一个子串。字符串 r 的从 第 i 个字符开始的后缀表示为 Suffix(i) ,也就是Suffix(i)=r[i..len(r)] 。   例子: 1 字符串: "banana"的所有后缀如下: 2 3 0 banana 5 a 4 1 anana 对所有后缀排序 3 ana 5 2 nana ----------------> 1 anana 6 3 ana 字典序 0 banana 7 4 na 4 na 8 5 a 2 nana 9 10 所以 "banana" 的后缀数组SA为: {5, 3, 1, 0, 4, 2} 名次数组:名次数组Rank[i]保存的是以i开头的后缀的排名,与SA互为逆。简单的说,后缀数组是“排在第几的是谁”,名次数组是“你排第几”。 构造算法   求解后缀数组的算法主要有两种:

2015长春网络赛 1006(后缀数组或者最小表示法)

允我心安 提交于 2019-12-19 05:02:50
给一个字符串,这个字符串是首位连起来的,要我们输出从哪个位置开始,顺时针走,还是你时针走,字典序最大 如果字典序最大的字符串有多个,开始的下标越小越好,如果开始的下标又相同,那么顺时针的优先。 原字符串为abab,那么只要在后面加上原字符串,变成abababab#,#是一个很小的字符, 然后进行后缀数组,sa[n-1]就是顺指针字典序最大的下标,n为abababab#的长度 逆时针,只要将字符串倒过来,babababa@,@是一个很大的字符, 然后进行后缀数组, 那么只要遍历rank[0,m) ,找到最大的rank所对应的下标就是逆时针字典序最大的下标。 1 #pragma warning(disable:4996) 2 #include <stdio.h> 3 #include <string.h> 4 #include <math.h> 5 #include <vector> 6 #include <queue> 7 #include <stack> 8 #include <map> 9 #include <set> 10 #include <algorithm> 11 #include <iostream> 12 #include <functional> 13 #include <string> 14 const int INF = 1<<30; 15 const

数据结构与算法--栈、队列(栈)

|▌冷眼眸甩不掉的悲伤 提交于 2019-12-18 02:38:31
hello,everybody. 我们又见面了,这次我们一起来学习数据结构中,非常有意思的两种结构—Stack ,Queue. 首先来学习一下栈: 栈: 限定只在表尾进行删除插入操作的线性表。 顾名思义,栈是一种特殊的线性表。它特殊在什么地方呢?它只能在表尾进行插入或删除操作,又就意味着,它只能是先进后出。给大家举个现实中,利用栈的例子。我们都用浏览器浏览过网页,我们对浏览器的前进后退按钮一定都不陌生。当我们打开第一个网页时,有一个图片链接,于是我们又跳到了第二个网页。此时,又有一个文字链接,我们又跳到了第三个网页。此时,我点击浏览器的后退按钮,我们会回到第二个网页。再点击浏览器的后退按钮,我们又跑到了第一个网页。是不是最先打开的第一个网页,是最后一个恢复的?是不是,先进后出? 看来,我们在学习第二章线性表时,付出的心血没有白费。看看,我在学习栈与队列时,感到很轻松,因为它讲的一些概念,我都掌握了。所以,我们在学习知识时,一定要踏实,耐心。付出一定会有回报的,你用心付出,回报巨大,回报明显。你不用心付出,回报微小,回报不明显。你不付出,只是随意看看,那么当别人说起这些知识时,你也可以装下B。所以,付出是有回报的。只是为了,回报巨大,回报明显,我们需要用心,态度要端正。 我们把允许删除的一端称为栈顶(Top),另一端称为栈底(Bottom). 不含任何数据元素的栈称为空栈

字符串匹配的KMP算法

孤街浪徒 提交于 2019-12-17 08:31:53
原理 字符串匹配 是计算机的基本任务之一。 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务, Knuth-Morris-Pratt算法 (简称KMP)是最常用的之一。它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth。 这种算法不太容易理解,网上有很多 解释 ,但读起来都很费劲。直到读到 Jake Boxer 的文章,我才真正理解这种算法。下面,我用自己的语言,试图写一篇比较好懂的KMP算法解释。 1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。 2. 因为B与A不匹配,搜索词再往后移。 3. 就这样,直到字符串有一个字符,与搜索词的第一个字符相同为止。 4. 接着比较字符串和搜索词的下一个字符,还是相同。 5. 直到字符串有一个字符,与搜索词对应的字符不相同为止。 6. 这时,最自然的反应是,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率很差,因为你要把"搜索位置"移到已经比较过的位置,重比一遍。 7. 一个基本事实是,当空格与D不匹配时,你其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息

彻底搞懂KMP,一篇就够了

南楼画角 提交于 2019-12-13 07:24:49
前言: 看毛片算法漫画讲解超幽默有爱~ 一,KMP算法解决什么类型的问题 String str1 = "bacbababadababacambabacaddababacasdsd" ; String str2 = "ababaca" ; 由以上字符串我们知道,str1有两处包含str2 分别在str1的下标为10,26的位置 “bacbababad * * ababaca * * mbabacadd * * ababaca * * sdsd” ; 二,算法讲解与说明 一般匹配字符串时,我们从目标字符串str1(假设长度为n)的第一个下标选取和str2长度(长度为m)一样的子字符串进行比较,直到str1的末尾(实际比较时,下标移动到n-m)。这样子的复杂度就是O(n*m)。而KMP算法的复杂度可以优化为O(n+m) 简化时间复杂度的原因:充分利用了目标字符串str2的性质(比如里面部分的字符串的重复性,即使不存在重复字段,在比较时实现最大的移动量。 三,考察目标字符串str2 ababaca 这里我们先要计算一个长度为m的转移函数next。next数组的含义就是一个固定字符串的最长前缀和最长后缀相同的长度。 比如:abcjkdabc,那么这个数组的最长前缀和最长后缀相同的话必然是abc。 cbcbc,这个数组的最长前缀以及最长后缀相同就是cbc。 abcbc

后缀数组的应用

ⅰ亾dé卋堺 提交于 2019-12-07 01:13:44
后缀排序 题目链接: P3809【模板】后缀排序 sa[i]表示排名为i的后缀的起始位置的下标 #include<bits/stdc++.h> using namespace std; const int maxx = 1e6+10; char s[maxx]; int y[maxx],x[maxx],c[maxx],sa[maxx]; int rk[maxx],height[maxx],wt[30]; int n,m; void get_sa() { for(int i=1;i<=n;i++)c[x[i]=s[i]]++; //c数组是桶 //x[i]是第i个元素的第一关键字 for(int i=2;i<=m;i++)c[i]+=c[i-1]; for(int i=n;i>=1;i--)sa[c[x[i]]--]=i; for(int k=1;k<=n;k<<=1) { int num=0; for(int i=n-k+1;i<=n;i++)y[++num]=i; //y[i]表示第二关键字排名为i的数,第一关键字的位置 //第n-k+1到第n位是没有第二关键字的,所以排名在最前面 for(int i=1;i<=n;i++)if(sa[i]>k)y[++num]=sa[i]-k; for(int i=1;i<=m;i++)c[i]=0; for(int i=1;i<=n;i++

后缀数组模板

隐身守侯 提交于 2019-12-06 11:16:45
模板题 学了很久,算是解决了一块心病, 虽然大致能理解,但现在也只是停留在写模板的程度 存个模板先 #include <iostream> #include <stdio.h> #include <string.h> #include <stdlib.h> using namespace std; const int MAXN=1e6+10; char s[MAXN]; int n,m,sa[MAXN],rk[MAXN],tp[MAXN],c[MAXN],height[MAXN]; void getsa(){ m='z'; for(int i=1;i<=n;i++) c[rk[i]=s[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i-1]; for(int i=n;i>=1;i--) sa[c[rk[i]]--]=i; for(int w=1,p=0;p<n;w<<=1,m=p){ p=0; for(int i=n-w+1;i<=n;i++) tp[++p]=i; for(int i=1;i<=n;i++) if(sa[i]>w) tp[++p]=sa[i]-w; for(int i=1;i<=m;i++) c[i]=0; for(int i=1;i<=n;i++) c[rk[i]]++; for(int i=1;i<=m;i++) c[i]+=c[i

【后缀数组】【LuoguP2852】 [USACO06DEC]牛奶模式Milk Patterns

不打扰是莪最后的温柔 提交于 2019-12-05 17:48:26
题目链接 题目描述 农夫John发现他的奶牛产奶的质量一直在变动。经过细致的调查,他发现:虽然他不能预见明天产奶的质量,但连续的若干天的质量有很多重叠。我们称之为一个“模式”。 John的牛奶按质量可以被赋予一个0到1000000之间的数。并且John记录了N(1<=N<=20000)天的牛奶质量值。他想知道最长的出现了至少K(2<=K<=N)次的模式的长度。比如1 2 3 2 3 2 3 1 中 2 3 2 3出现了两次。当K=2时,这个长度为4。 思路: 实际上就是求可重叠的 \(k\) 次最长子串 这里给出单调队列的代码 代码 #include<iostream> #include<cstdio> #include<algorithm> #define maxn 20010 using namespace std; int n, K; int a[maxn], cnt, b[maxn]; void init_hash() { for (int i = 1; i <= n; ++i) { scanf("%d", &a[i]); b[i] = a[i]; } sort(b + 1, b + n + 1); cnt = unique(b + 1, b + n + 1) - b - 1; for (int i = 1; i <= n; ++i) a[i] = lower_bound