后缀数组(一)

o(︶︿︶)o 唉,也是为了应付知识储备太少,万一遇到了类似的题不知道用啥算法就蛋疼了,所以来恶补一下这些东西。

囤一发模板,详细讲解请见2009罗橞骞的论文《后缀数组--处理字符串的有力工具》,基本网上所有的讲解都是来自这篇文章,代码也是这篇论文上的,就不说啥了。

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100010
char s[MAXN];
int A[MAXN];
//为了方便基数排序,我们把s中的字符转换成数字.s和A的下标使用统一0-n-1
int sa[MAXN],rank[MAXN];//最后结果的rank和sa
int Count[MAXN];//基数排序计数器
int l[MAXN],r[MAXN],tmp[MAXN];//基数排序共有两个关键字,r为第二关键字基数排序结果,l值即临时rank值.
int n,maxn;//计数上界
bool comp(int *A,int a,int b,int len)//字符串比较
{
    return A[a]==A[b]&&A[a+len]==A[b+len];
}
int main()
{
    /*省略读入等奇怪的过程*/
    int i,j,k,*x=l,*y=r;//后面会整体交换l,r为了方便使用指针
    for (i=0;i<maxn;i++)    Count[i]=0;
    for (i=0;i<n;i++)   Count[x[i]=A[i]]++;//第一次基数排序
    for (i=1;i<maxn;i++)    Count[i]+=Count[i-1];
    for (i=n-1;i>=0;i--)    sa[--Count[x[i]]]=i;//初始的sa
    for (k=1,i=1;i<n;k<<=1,maxn=i)
    {
        for (i=0,j=n-i;j<n;j++) y[i++]=i;//第二次基数排序
        for (j=0;j<n;j++)   if (sa[j]>=k)   y[i++]=sa[j]-k;
        for (j=0;j<n;j++)   tmp[j]=x[y[j]];
        for (j=0;j<maxn;j++)    Count[j]=0;
        for (j=0;j<n;j++)   Count[tmp[j]]++;
        for (j=1;j<maxn;j++)    Count[j]+=Count[j-1];
        for (j=n-1;j>=0;j--)    sa[--Count[tmp[j]]]=y[j];//更新sa
        for (swap(x,y),i=1,x[sa[0]]=0,j=1;j<n;j++)  x[sa[j]]=comp(y,sa[j-1],sa[j],k)?i-1:i++;//更新rank
        //在更新过程中可能有两字符串rank值相同,此时比较两字符串是否完全相同来区分rank值
        //由于y数组在被用来更新sa后已经无用(下一次会重新求),节省空间使用y保存rank
    }
}

o(︶︿︶)o 唉,也是为了应付知识储备太少,万一遇到了类似的题不知道用啥算法就蛋疼了,所以来恶补一下这些东西。

版权声明:本文为博主原创文章,转载请注明出处http://blog.csdn.net/hitwhacmer1

时间: 2024-10-07 04:00:32

后缀数组(一)的相关文章

SPOJ 705 Distinct Substrings(后缀数组)

[题目链接] http://www.spoj.com/problems/SUBST1/ [题目大意] 给出一个串,求出不相同的子串的个数. [题解] 对原串做一遍后缀数组,按照后缀的名次进行遍历, 每个后缀对答案的贡献为n-sa[i]+1-h[i], 因为排名相邻的后缀一定是公共前缀最长的, 那么就可以有效地通过LCP去除重复计算的子串. [代码] #include <cstdio> #include <cstring> #include <algorithm> usi

hdu5769--Substring(后缀数组)

题意:求含有某个字母的某个字符串的不同子串的个数 题解:后缀数组,记录每个位置距离需要出现的字母的距离就可以了.因为不太了解后缀模版卡了一会,还是很简单的. 记住sa和height数组都是1-n的下标. //后缀数组 #include <stdio.h> #include <cstring> #include <iostream> #include <algorithm> using namespace std; typedef long long ll;

hdu 3518 Boring counting 后缀数组LCP

题目链接 题意:给定长度为n(n <= 1000)的只含小写字母的字符串,问字符串子串不重叠出现最少两次的不同子串个数; input: aaaa ababcabb aaaaaa # output 2 3 3 思路:套用后缀数组求解出sa数组和height数组,之后枚举后缀的公共前缀长度i,由于不能重叠,所以计数的是相邻height不满足LCP >= i的. 写写对后缀数组倍增算法的理解: 1.如果要sa数组对应的值也是1~n就需要在最后加上一个最小的且不出现的字符'#',里面y[]是利用sa数

【tyvj1860】后缀数组

描述 我们定义一个字符串的后缀suffix(i)表示从s[i]到s[length(s)]这段子串.后缀数组(Suffix array)SA[i]中存放着一个排列,满足suffix(sa[i])<suffix(sa[i+1]) 按照字典序方式比较定义height[i]表示suffix(sa[i])与suffix(sa[i-1])之间的最长公共前缀长度,其中height[1]=0你的任务就是求出SA和height这两个数组.字符串长度<=200000 输入格式 一行,为描述中的字符串(仅会出现小写

BZOJ 3238 AHOI 2013 差异 后缀数组+单调栈

题目大意: 思路:一看各种后缀那就是后缀数组没跑了. 求出sa,height之后就可以乱搞了.对于height数组中的一个值,height[i]来说,这个值能够作为lcp值的作用域只在左边第一个比他小的位置到右边第一个比他小的位置.这个东西很明显可以倍增RMQ+二分/单调栈. 之后就是数学题了 Σlen[Ti] + len[Tj] = (len + 1) * len * (len - 1),之后吧所有求出来的Σ2 * lcp(Ti,Tj)减掉就是答案. 记得答案开long long CODE:

hdu 5030 Rabbit&#39;s String(后缀数组&amp;二分)

Rabbit's String Time Limit: 40000/20000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 288    Accepted Submission(s): 108 Problem Description Long long ago, there lived a lot of rabbits in the forest. One day, the

hdu 4416 Good Article Good sentence(后缀数组&amp;思维)

Good Article Good sentence Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 2308    Accepted Submission(s): 649 Problem Description In middle school, teachers used to encourage us to pick up pre

uva 10829 - L-Gap Substrings(后缀数组)

题目链接:uva 10829 - L-Gap Substrings 题目大意:给定一个字符串,问有多少字符串满足UVU的形式,要求U非空,V的长度为g. 解题思路:对字符串的正序和逆序构建后缀数组,然后枚举U的长度l,每次以长度l分区间,在l和l+d+g所在的两个区间上确定U的最大长度. #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> using nam

poj 3693 Maximum repetition substring(后缀数组)

题目链接:poj 3693 Maximum repetition substring 题目大意:求一个字符串中循环子串次数最多的子串. 解题思路:对字符串构建后缀数组,然后枚举循环长度,分区间确定.对于一个长度l,每次求出i和i+l的LCP,那么以i为起点,循环子串长度为l的子串的循环次数为LCP/l+1,然后再考虑一下从i-l+1~i之间有没有存在增长的可能性. #include <cstdio> #include <cstring> #include <vector>

uva 10526 - Intellectual Property(后缀数组)

题目链接:uva 10526 - Intellectual Property 题目大意:给定两个文本,问说下面一个文本中在哪些位置上抄袭了上面个一个文本的,输出n个抄袭位置(不足n个情况全部输出),按照长度优先输出,长度相同的输出位置靠前的. 注意:空格,回车都算一个字符:一段字符只能是抄袭上面的一部分,比如上:NSB*SB 下:NSB 答案:NSB. 解题思路:将两个文本连接在一起,中间用没有出现的字符分割,然后处理处后缀数组,根据height数组的性质,求出哪些位置匹配的长度不为0(注意匹配