后缀数组 TYVJ P1860 后缀数组

/*P1860 后缀数组
时间: 1000ms / 空间: 131072KiB / Java类名: Main
描述

我们定义一个字符串的后缀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
输入格式

一行,为描述中的字符串(仅会出现小写字母)
输出格式

共两行,每行n个数,第一行为sa[i],第二行为height[i],其中每行的数均用空格隔开
测试样例1

输入

aabaaaab
输出

4 5 6 1 7 2 8 3
0 3 2 3 1 2 0 1*/
//本题算法就是题目名,而且还是后缀数组最简单的应用。
//关于后缀数组我不想多说,推荐 算法合集之《后缀数组——处理字符串的有力工具》
//有时真想有人给我讲讲,自学是非常非常痛苦的。
//但有2个点超时,不过不管了。
#include<cstdio>
#include<iostream>
#include<cstring>
#define N 200008
using namespace std;
int n,sa[2][N],rk[2][N],a[N],v[N],k,h[N];
char ch[N];
void geng(int sa[N],int rk[N],int SA[N],int RK[N])
{
for(int i=1;i<=n;i++)
v[rk[sa[i]]]=i;
for(int i=n;i;i--)
if(sa[i]>k)
SA[v[rk[sa[i]-k]]--]=sa[i]-k;
for(int i=n-k+1;i<=n;i++)
SA[v[rk[i]]--]=i;
for(int i=1;i<=n;i++)
RK[SA[i]]=RK[SA[i-1]]+(rk[SA[i]]!=rk[SA[i-1]]||rk[SA[i]+k]!=rk[SA[i-1]+k]);
return;
}
int main()
{
gets(ch+1);
n=strlen(ch+1);
for(int i=1;i<=n;i++)
a[i]=ch[i]-‘a‘+1;
int p=0,q=1;
for(int i=1;i<=n;i++)
v[a[i]]++;
for(int i=2;i<27;i++)
v[i]+=v[i-1];
for(int i=1;i<=n;i++)
sa[p][v[a[i]]--]=i;
for(int i=1;i<=n;i++)
rk[p][sa[p][i]]=rk[p][sa[p][i-1]]+(a[sa[p][i]]!=a[sa[p][i-1]]);
for(k=1;k<n;k<<=1)
{
geng(sa[p],rk[p],sa[q],rk[q]);
swap(p,q);
}
for(int i=1;i<=n;i++)
printf("%d ",sa[p][i]);
printf("\n");
k=0;
for(int i=1;i<=n;i++)
if(rk[p][i]==1)
h[1]=0;
else
{
int j=sa[p][rk[p][i]-1];
for(;a[i+k]==a[j+k];k++);
h[rk[p][i]]=k;
if(k>0)
k--;
}
for(int i=1;i<=n;i++)
printf("%d ",h[i]);
return 0;
}

时间: 2024-10-02 18:27:49

后缀数组 TYVJ P1860 后缀数组的相关文章

[UOJ#35] [UOJ后缀数组模板题] 后缀排序 [后缀数组模板]

后缀数组,解决字符串问题的有利工具,本题代码为倍增SA算法 具体解释详见2009年国家集训队论文 1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cmath> 7 #include <ctime> 8 9 using namespace

【后缀数组】关于后缀数组模板的注解续

int wa[N], wb[N], ws[N], wv[N] int rank[N], height[N] #此处N比输入的N要多1,为人工添加的一个字符,用于避免CMP时越界 void getSA(int *r, int *sa, int n, int m) int i, j, p, *x = wa, *y = wb, *t # bucket清空 for(i = 0; i < m; i++) ws[i] = 0 #进行一次基数排序 for(i = 0; i < n; i++) ws[x[i]

HDU - 6704 K-th occurrence (后缀数组+主席树/后缀自动机+线段树合并+倍增)

题意:给你一个长度为n的字符串和m组询问,每组询问给出l,r,k,求s[l,r]的第k次出现的左端点. 解法一: 求出后缀数组,按照排名建主席树,对于每组询问二分或倍增找出主席树上所对应的的左右端点,求第k大的下标即可. 1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e5+10,mod=998244353; 5 char buf[N]; 6 int s[N],sa[

C++语言中数组指针和指针数组彻底分析

#################################                              ##       基本知识               ##                              ################################# 当然我们一切都是从最简单的内建类型开始,最后我会做一些推广.先看一下基本的形式,我们从这里起步! Cpp代码 --------------指针---------------- int a

软件工程课程作业(四)--返回一个整数数组中最大子数组的和

伙伴链接:http://www.cnblogs.com/haoying1994/ 一.设计思想 本实验要求输入一个正负数混合的整型数组,长度不限,在此数组的所有子数组中找到和最大的数组,并求出相应数组的和,且时间复杂度为O(n).我们在课堂上共同讨论了多种解决方案,这些将在下面可能的解决方案中展示,在听了同学的思路和老师的讲解之后, 我们最终选取了老师课堂上描述的比较简便的思路.如下: 在输入数组的环节,采用for无限循环加if判断截止,直到触发回车键为止,将数组记录到Array中,数组长度记录

qsort 函数的使用——对普通数组、指针数组、二维数组中的元素进行排序

在ANSI C中,qsort函数的原型是 #include <stdlib.h> void qsort(void *base, size_t nmemb, size_t size, int (*compar) (const void *, const void *)); 解释:qsort函数对含有nmemb个元素的数组进行排序,而base指针指向数组的第一个元素.这个数组的元素个数由size指定. compar函数对qsort的比较操作进行定义,所以可以定制数字的比较,字符串的比较,甚至结构体

JavaScript - 一维数组、二维数组基础

<html> <head> <head> <body> <script language="javascript"> // 数组 var arr = ["wjp", 520, 'wcc', 13.14] ; for(var i=0; i<arr.length; i++){ alert(arr[i]); } // 数组为空undefined var arr2 = ["wjp",,51

PHP统计数组和唯一的数组

统计数组元素出现的频度 array_count_values() 函数返回一个包含关联键/值对的数组.其形式为z array array_count_values(array array) 其中每个键表示input_array 中的一个值,相应的值表示这个键在input_array 中出现(作为值) 的频度.示例如下: $states = array("Ohio" , "Iowa" , "Arizona" , "Iowa" ,

数组指针和指针数组的区别

数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长.也就是说执行p+1时,p要跨过n个整型数据的长度. 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组. p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++;       //该语句执行过后,也就是