十、后缀数组

模板:

1.快排:

var

rank,height,h:array [0..300000] of qword;

//rank[i]:i的后缀的排名;

//height[i]:lcp(s[a[i,2]...len],s[a[i-1,2]...len]);

//h[i]:lcp(s[i...len],s[a[rank[i]-1,2]...len]);

//h[i]>=h[i]-1;

a:array [1..300000,1..2] of qword;

f:array [1..300000] of boolean;

s:string;

i,j,m,n,k,mm:longint;

x:qword;

procedure cha(l,r:longint);

var

i,j:longint;

mid,t:qword;

begin

i:=l;

j:=r;

mid:=a[(l+r) div 2,1];

while i<=j do

begin

while a[i,1]<mid do inc(i);

while a[j,1]>mid do dec(j);

if (i<=j) then

begin

t:=a[i,1];

a[i,1]:=a[j,1];

a[j,1]:=t;

t:=a[i,2];

a[i,2]:=a[j,2];

a[j,2]:=t;

inc(i);

dec(j);

end;

end;

if j>l then cha(l,j);

if i<r then cha(i,r);

end;

begin

assign(input,‘sss.in‘);

assign(output,‘sss.out‘);

reset(input);

rewrite(output);

readln(s);

for i:=1 to length(s) do

begin

a[i,1]:=ord(s[i])-ord(‘a‘)+1;

a[i,2]:=i;

rank[i]:=a[i,1];

end;

m:=1;

while n<>length(s) do

begin

n:=0;

if m<>0 then

for i:=1 to length(s) do

begin

x:=rank[i]*1000000;

x:=x+rank[i+m];

a[i,1]:=x;

a[i,2]:=i;

end;

cha(1,length(s));

n:=1;

rank[a[1,2]]:=1;

for i:=2 to length(s) do

begin

if a[i,1]<>a[i-1,1] then

inc(n);

rank[a[i,2]]:=n;

end;

m:=m*2;

end;

for i:=1 to length(s) do

write(a[i,2],‘ ‘);

writeln;

j:=0;

for i:=1 to length(s) do

begin

if j>0 then dec(j);

while (rank[i]-1<>0) and (s[i+j]=s[a[rank[i]-1,2]+j]) do inc(j);

h[i]:=j;

height[rank[i]]:=j;

end;

for i:=1 to length(s) do

write(height[i],‘ ‘);

writeln;

for i:=1 to length(s) do

write(h[i],‘ ‘);

writeln;

close(input);

close(output);

end.

2.桶排

var

rank,sa,lis,a:array [1..10000] of longint;

f:array [1..10000] of boolean;

s:string;

i,j,m,n,k:longint;

begin

readln(s);

m:=1;

for i:=1 to length(s) do

rank[i]:=ord(s[i])-ord(‘a‘)+1;

while n<>length(s) do

begin

n:=0;

for i:=1 to length(s) do

a[i]:=rank[i]*100+rank[i+m];

fillchar(f,sizeof(f),false);

for i:=1 to length(s) do

begin

if not f[a[i]] then

begin

inc(n);

f[a[i]]:=true;

end;

end;

k:=0;

for i:=1 to 2626 do

if f[i] then

begin

inc(k);

lis[i]:=k;

end;

for i:=1 to length(s) do

rank[i]:=lis[a[i]];

m:=m*2;

end;

for i:=1 to length(s) do

write(rank[i],‘ ‘);

writeln;

end.

倍增算法解释:

样例1:

sa:1   2   3   5   1   1   2   4

第一次排序rank:102 203 305 501 101 102 204 400

sa:2   3   5   7   1   2   4   6

第二次排序rank:205 307 501 702 104 206 400 600

sa:2   4   6   8   1   4   5  7

样例2:

sa:1   1   2   1   1   1   1   2

第一次排序rank:101 102 201 101 101 101 102 200

sa:1   2   4   1   1   1   2   3

第二次排序rank:104 201 401 101 102 103 200 300

sa:4   6   8   1   2   3   5   7

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-27 23:59:12

十、后缀数组的相关文章

「kuangbin带你飞」专题十八 后缀数组

layout: post title: 「kuangbin带你飞」专题十八 后缀数组 author: "luowentaoaa" catalog: true tags: - kuangbin - 字符串 - 后缀数组 传送门 倍增法 struct DA{ bool cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } int t1[maxn],t2[maxn],c[maxn]; int r

彻底弄懂后缀数组

  什么叫后缀数组  首先要知道什么叫后缀 ? 比如 字符串 abcdef  那么 abcdef    bcdef    cdef     def       ef       f 就叫做后缀  也就是从最后一个字母之前的一个字母开始一直到最后一个字母(所以所 bcd不是后缀 因为没有到最后一位f)  所构成的字符串就叫做后缀 至于后缀数组能干什么?我在这就不介绍了  这不是本文的重点!本文主要讲解后缀数组应该怎么写代码! 写本文的原因 但是自己之前读过很多后缀数组的文章  短短二三十代码  却

完全弄懂后缀数组

什么叫后缀数组  首先要知道什么叫后缀 比如 字符串 abcdef  那么 abcdef bcdef cdef def ef f 就叫做后缀  也就是从最后一个字母之前的一个字母开始一直到最后一个字母  所构成的字符串就叫做后缀 至于后缀数组能干什么?我在这就不介绍了  我想你既然知道后缀数组就一定知道他的用处 但是自己之前读过很多后缀数组的文章  短短二三十代码  却没有找到一篇博客从头到尾讲解的 自己断断续续一个月终于算是对倍增算法(就是一个名字  不必纠结什么叫倍增算法)的有个比较深入理解

学渣乱搞系列之后缀数组

学渣乱搞系列之后缀数组 by 狂徒归来 后缀数组,其nlogn的构造方法,比较麻烦,十几个循环,基数排序?计数排序?各种排序,各种凌乱,学渣表示鸭梨很大啊!学渣从<挑战程序设计竞赛>中偷学了一点nlog2n的构造方法. 字符串后缀(Suffix)是指从字符串的某个位置开始到其末尾的字符串子串.我们认为原串和空串也是后缀. 后缀数组(Suffix Array)指的是将某个字符的所有后缀按字典序排序后得到的数组.排序方式很多,时间复杂度也不同.有基数排序的倍增法o(nlogn),有DC3构造方法o

【后缀数组】【RMQ】HDU 6194 - string string string (2017ICPC沈阳网络赛)

string string string Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Problem Description Uncle Mao is a wonderful ACMER. One day he met an easy problem, but Uncle Mao was so lazy that he left the problem to you. I

POJ 1743 后缀数组:求最长不重叠子串

数据:这题弄了好久,WA了数十发,现在还有个例子没过,可却A了,POJ 的数组也太弱了. 10 1 1 1 1 1 1 1 1 1 1 这组数据如果没有那个n-1<10判断的话,输入的竟然是5,我靠-- 思路:这个题目关键的地方有两个:第一,重复的子串一定可以看作是某两个后缀的公共前缀,第二,把题目转化成去判定对于任意的一个长度k,是否存在长度至少为k的不重叠的重复的子串. 转化成判定问题之后,就可以二分去解答了.在验证判定是否正确时,我们可以把相邻的所有不小于k的height[]看成一组,然后

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 输入格式 一行,为描述中的字符串(仅会出现小写