poj_1743 后缀数组
题目大意
给定一串数字,长度为N。定义数字中的某个连续的子串为一个"theme",只要子串满足:
(1)长度 >= 5
(2)和该子串相同或者该子串的“变种串”在整串数字中出现次数大于1
(3)假设整串中有k个该子串及其“变种串”,那么其中至少有两个不相重叠
求满足要求的 "theme" 串的最长长度。
题目分析
(1)首先考虑将“变种”串和原子串相互比较的问题,对字符串中所有索引大于等于1的字符都用该字符减去前一个字符,这样得到串的差串之后,原theme和其“变种”就一样了,此时只需要求差串中的最长相同子串,且这些子串之间不重叠。
求最长相同子串,可以考虑使用后缀数组和height数组。显然,height越大,则两个子串的公共前缀越长,越有可能是最长相同子串。但是,题目对"theme"串的要求(3)至少两个不重叠,因此需要考虑height[i]在尽可能大的同时,保证SA[i]和SA[i-1]之间的差值要大于height[i]以保证不重叠。
(2)然后,试图求解是否存在长度为M的"theme"串。
容易看出,后缀Suffix(j)和Suffix(k)的最长公共前缀的长度为 height[rank[j]+1], height[rank[j]+2]...height[rank[k]]的最小值。i从1到N遍历,通过height[i]>=M将i分开,即将后缀分成若干组,每组中的后缀的公共前缀长度均大于等于M,且可以肯定组A中的某后缀t1和组B中的某后缀t2的公共前缀长度小于M。若存在这样的组,则可以确定找到了公共前缀大于等于M的子串,下一步需要确定这些子串不重叠。只需要在组内寻找 SA[i] 之间最大的查看,看是否大于子串的长度,若大于则可以确定不重叠。
(3)最后,求解"theme"串长度M的最大值,用二分法对"theme"串的可能长度进行二分求解,长度范围为0到N。每次二分得到中值M,先判断能否找到长度为k的"theme"串,若不能,则减小M,否则增加M。直到找到长度M最大的"theme"串。
实现(c++)
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#define MAX(a, b) a>b? a:b
#define MAX_ARRAY_SIZE 20005
#define LETTERS 10000 int gStrLen;
int gStr[MAX_ARRAY_SIZE];
int gCount[MAX_ARRAY_SIZE];
int gSuffixArray[MAX_ARRAY_SIZE];
int gRank[MAX_ARRAY_SIZE];
int gOrderBySecondKey[MAX_ARRAY_SIZE];
int gFirstKeyArray[MAX_ARRAY_SIZE];
int gHeight[MAX_ARRAY_SIZE]; bool Compare(int* arr, int a, int b, int step){
return arr[a] == arr[b] && arr[a + step] == arr[b + step];
} void GetStr(char* str){
memset(gStr, 0, sizeof(gStr));
gStrLen = strlen(str);
for (int i = 0; i < gStrLen; i++){
gStr[i] = str[i] - 'a' + 1;
}
gStr[gStrLen++] = 0;
} void GetSuffixArray(){
int n = gStrLen;
memset(gCount, 0, sizeof(gCount));
for (int i = 0; i < n; i++){
gRank[i] = gStr[i];
gCount[gRank[i]] ++;
}
for (int i = 1; i < LETTERS; i++){
gCount[i] += gCount[i - 1];
}
for (int i = n - 1; i >= 0; i--){
gSuffixArray[--gCount[gRank[i]]] = i;
}
int step = 1;
int* rank = gRank, *order_by_second_key = gOrderBySecondKey;
int m = LETTERS;
while (step < n){
int p = 0;
for (int i = n - step; i < n; i++){
order_by_second_key[p++] = i;
}
for (int i = 0; i < n; i++){
if (gSuffixArray[i] >= step){
order_by_second_key[p++] = gSuffixArray[i] - step;
}
}
for (int i = 0; i < n; i++){
gFirstKeyArray[i] = rank[order_by_second_key[i]];
}
for (int i = 0; i < m; i++){
gCount[i] = 0;
}
for (int i = 0; i < n; i++){
gCount[gFirstKeyArray[i]] ++;
}
for (int i = 1; i < m; i++){
gCount[i] += gCount[i - 1];
}
for (int i = n - 1; i >= 0; i--){
gSuffixArray[--gCount[gFirstKeyArray[i]]] = order_by_second_key[i];
}
int* tmp = rank;
rank = order_by_second_key;
order_by_second_key = tmp;
rank[gSuffixArray[0]] = 0;
p = 0;
for (int i = 1; i < n; i++){
if (Compare(order_by_second_key, gSuffixArray[i], gSuffixArray[i - 1], step)){
rank[gSuffixArray[i]] = p;
}
else{
rank[gSuffixArray[i]] = ++p;
}
}
m = p + 1;
step *= 2;
}
} void GetHeight(){
int n = gStrLen;
for (int i = 1; i < n; i++){
gRank[gSuffixArray[i]] = i;
}
int k = 0, j;
gHeight[0] = 0;
for (int i = 0; i < n - 1; i++){
j = gSuffixArray[gRank[i] - 1];
if (k){
k--;
}
while (i + k < n && j + k < n && gStr[i + k] == gStr[j + k]){
k++;
}
gHeight[gRank[i]] = k;
}
}
bool Find(int k){
int end = 1;
int min_pos, max_pos;
while (end < gStrLen){
max_pos = min_pos = gSuffixArray[end-1];
while (end < gStrLen && gHeight[end] >= k - 1){
if (min_pos > gSuffixArray[end]){
min_pos = gSuffixArray[end];
}
if (max_pos < gSuffixArray[end]){
max_pos = gSuffixArray[end];
} end ++;
}
if (max_pos - min_pos >= k){
return true;
}
end ++;
}
return false;
}
void printstr(int n){
printf("string = \n");
for (int i = 0; i < n; i++){
printf("%d ", gStr[i]);
}
printf("\n");
}
void printsuffix(int n){
printf("suffix = \n");
for (int i = 0; i < n; i++){
printf("%d ", gSuffixArray[i]);
}
printf("\n");
}
void printheigt(int n){
printf("height = \n");
for (int i = 0; i < n; i++){
printf("%d ", gHeight[i]);
}
printf("\n");
}
int main(){
int n;
while (true){
scanf("%d", &n); if (n == 0){
break;
} for (int i = 0; i < n; i++){
scanf("%d", &gStr[i]);
}
int min = 100;
for (int i = 1; i < n; i++){
gStr[i - 1] = gStr[i] - gStr[i - 1];
min = gStr[i - 1] < min ? gStr[i - 1] : min;
}
min--;
for (int i = 0; i < n; i++){
gStr[i] -= min;
}
gStr[n-1] = 0;
gStrLen = n; GetSuffixArray();
GetHeight();
// printstr(n);
// printsuffix(n);
// printheigt(n);
int beg = 0, end = n, mid, max;
bool flag = true;
while (beg < end){
mid = (beg + end) / 2;
if (Find(mid)){
beg = mid + 1;
max = mid;
}
else{
if (mid <= 5){
flag = false;
break;
}
end = mid;
}
}
if (!flag){
printf("0\n");
}
else{
printf("%d\n", max);
}
}
return 0;
}
poj_1743 后缀数组的更多相关文章
- 后缀数组的倍增算法(Prefix Doubling)
后缀数组的倍增算法(Prefix Doubling) 文本内容除特殊注明外,均在知识共享署名-非商业性使用-相同方式共享 3.0协议下提供,附加条款亦可能应用. 最近在自学习BWT算法(Burrows ...
- BZOJ 4199: [Noi2015]品酒大会 [后缀数组 带权并查集]
4199: [Noi2015]品酒大会 UOJ:http://uoj.ac/problem/131 一年一度的“幻影阁夏日品酒大会”隆重开幕了.大会包含品尝和趣味挑战两个环节,分别向优胜者颁发“首席品 ...
- BZOJ 1692: [Usaco2007 Dec]队列变换 [后缀数组 贪心]
1692: [Usaco2007 Dec]队列变换 Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 1383 Solved: 582[Submit][St ...
- POJ3693 Maximum repetition substring [后缀数组 ST表]
Maximum repetition substring Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 9458 Acc ...
- POJ1743 Musical Theme [后缀数组]
Musical Theme Time Limit: 1000MS Memory Limit: 30000K Total Submissions: 27539 Accepted: 9290 De ...
- 后缀数组(suffix array)详解
写在前面 在字符串处理当中,后缀树和后缀数组都是非常有力的工具. 其中后缀树大家了解得比较多,关于后缀数组则很少见于国内的资料. 其实后缀数组是后缀树的一个非常精巧的替代品,它比后缀树容易编程实现, ...
- 【UOJ #35】后缀排序 后缀数组模板
http://uoj.ac/problem/35 以前做后缀数组的题直接粘模板...现在重新写一下模板 注意用来基数排序的数组一定要开到N. #include<cstdio> #inclu ...
- 【BZOJ-2119】股市的预测 后缀数组
2119: 股市的预测 Time Limit: 10 Sec Memory Limit: 259 MBSubmit: 334 Solved: 154[Submit][Status][Discuss ...
- 【BZOJ-4698】Sandy的卡片 后缀数组
4698: Sdoi2008 Sandy的卡片 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 140 Solved: 55[Submit][Stat ...
随机推荐
- 【Unity/C#】DateTime时间字符串,月份用英文显示
制作一个钟表,要求效果如下图: 由于每一部分的字体大小不同,我分别使用了不同的Text控件.(不懂dalao们有没有更科学的办法) 把这些Text控件包含在一个Object下,给该Object定义一个 ...
- SQL2005 全文检索超时的解决方案
如果没有 Internet 连接的服务器上运行的 SQL Server 2005 实例中运行全文查询时,您可能会遇到 45 秒钟的延迟 详细的解释请查看http://support.microsoft ...
- archdexls主题设置每页显示游戏数目
archdexls主题,沒调整前,每页显示10个,这显然不够,尤其在搜狗浏览器上,由于这个主题只有触发下拉滚动条,才会自动在同一页面显示下一页,因此只显示10个甚至不能触发显示下一页这个动作. 原来设 ...
- 去掉CSS中的表达式Expression
在IE中,CSS是可以嵌入js表达式的,可以在CSS类中定义,但是将含有表达CSS类从DOM对象中移除,样式表达式是不会失效的. 经过研究找到了答案,需要使用js调用style对象的removeExp ...
- 【Java 线程的深入研究4】ThreadPoolExecutor运转机制详解
hreadPoolExecutor机制 一.概述 1.ThreadPoolExecutor作为java.util.concurrent包对外提供基础实现,以内部线程池的形式对外提供管理任务执行,线程调 ...
- 新兵训练营课程——环境与工具Java[转]
原文地址:http://weibo.com/p/1001643874239169320051 程序员在开发过程中会用到很多工具来提升开发和协作效率,这次介绍的是目前微博平台在开发过程中用到的一些工具, ...
- u3d读取xml txt
u3d读取xml文件和u3d 读取txt外部文件 using UnityEngine;using System.Collections; using System.Xml;using System.X ...
- [转]lsof详解
lsof是一个功能强大的诊断工具,它可以通过进程与打开的文件进行联系,可以列出一个进程打开的所有文件信息. 1 寻找与打开的文件相关联的进程通过指定文件,可以发现正在使用这个文件的进程# lsof / ...
- url传参错误的痛
今天用一下方法给后台传参数: var url = 'patrolpoint!totalHistoryPage.action' + '?patrolPoint.batchOnTime=' ...
- git 分支的创建、合并、删除
基本概念与命令 分支(branch):每次提交,Git都把提交的内容串成一条时间线,这条时间线就是一个分支 . git 分支的创建 git branch branchName git ...