poj 3581 后缀数组 详解

2024-05-28 05:08
文章标签 数组 详解 后缀 poj 3581

本文主要是介绍poj 3581 后缀数组 详解,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这个题折腾了快一个月,终于今晚又奋战了4个小时,AC掉了

题目:http://poj.org/problem?id=3581

首先看我写这个后缀数组教程,其实还不错http://blog.csdn.net/u011026968/article/details/20851295

关于第一个位置,反向读入,然后求后缀数组,找最小位置就好

第二个位置比较麻烦,参考这个博客的例子:http://bbezxcy.iteye.com/blog/1420546

大致思路:

    由于需要翻转,所以在输入时就按照反序输入。比如样例输入是5     10 1 2 3 4。我们从后向前读入就变为5     4 3 2 1 10。对这列数求出后缀数组。在大于2的后最中找到最小的后缀并输出。对于剩下的前缀s,我们把s串接到自己后面,也就是ss。再对这个串求出后缀数组,然后再把s中最小的前缀输出。最后把剩下的串输出。

 

对于第二步为什么要复制剩余串接在后面,用下面案例说明

6

10 1 2 2 3 4

 

第一步翻转后得到

4 3 2 2 1 10

 

求出后缀数组后得到最小的后缀便是:1 10,将其输出

剩下来的串是 4 3 2 2.

 

我们如果直接从剩余串中找到最小后缀的话会产生以下结果。

最小后缀是 2,输出。

输出剩余串 4 3 2。

最后得到1 10 2 4 3 2  很明显是wrong的

 

 

我们把剩余的串复制到剩余串的后面。

对 4 3 2 2 4 3 2 2求出后缀数组。

得到前四个字符的最小的后缀是 2 2,输出。

输出剩余串 4 3.

得到1 10 2 2 4 3 

 

这里解释了为啥不能直接对剩下的串求后缀数组

我个人除了很多问题,,,,我再想想做个总结,随后附上


/*******************************************************/
//POJ 3581 后缀数组   by Pilgrim
//注意:1、此代码中k是全局变量 别乱用
//     2、algorithm
//     3、注意此题的字典序的定义,跟往常不一样的
//     4、因为有负数所以最小的应该是int的下限而不是0
/******************************************************/#include <string>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <vector>#define MAXN 300005*2
#define INF -200000000
//0x80000000using namespace std;int n,k,pp,mm;
int num[MAXN],rr[MAXN];
int Rank[MAXN],tmp[MAXN],sa[MAXN];bool cmpSa(int i, int j)
{if(Rank[i]!=Rank[j]){return Rank[i]<Rank[j];}else{int ik = i+k<=n?Rank[i+k]:-INF-1;int jk = j+k<=n?Rank[j+k]:-INF-1;return ik<jk;}
}bool cmpSa2(int i, int j)
{if(Rank[i]!=Rank[j]){return Rank[i]<Rank[j];}else{int ik = i+k<=pp?Rank[i+k]:-INF-1;int jk = j+k<=pp?Rank[j+k]:-INF-1;return ik<jk;}
}bool cmpSS(int i,int j)
{return rr[i]<rr[j];
}void con_sa(int s,int e)
{int i,j;//sort(tmp+s,tmp+e+1,cmpSS);for(i=s;i<=e;i++)Rank[i]=rr[i];Rank[e]=INF;//printf("%d tmp=%d rank=%d\n",i,tmp[i],Rank[tmp[i]]);/*此时的rank已经能表示相对大小*/for(k=1;k<=e;k*=2){if(mm){pp=e;sort(sa+s,sa+e+1,cmpSa2);}else{sort(sa+s,sa+e+1,cmpSa);}tmp[sa[s]]=s;for(i=s+1;i<=e;i++){tmp[sa[i]]=tmp[sa[i-1]]+(cmpSa(sa[i-1],sa[i])?1:0);}for(i=s;i<=e;i++)Rank[i]=tmp[i];}
}void show(int p1,int p2)
{for(int i=p1;i<n;i++)printf("%d\n",num[i]);for(int i=p2;i<p1;i++)printf("%d\n",num[i]);for(int i=0;i<p2;i++)printf("%d\n",num[i]);
}void Init()
{memset(tmp,0,sizeof(tmp));memset(Rank,0,sizeof(Rank));memset(sa,0,sizeof(sa));for(int i=0;i<n;i++){scanf("%d",&num[i]);rr[n-i-1] = num[i];/*rr是整个反转后的串,*/sa[i]=i;}sa[n]=n;for(int i=0;i<=n;i++){num[i]=rr[i];tmp[i]=i;}
}void Init2(int e)
{memset(tmp,0,sizeof(tmp));memset(Rank,0,sizeof(Rank));memset(sa,0,sizeof(sa));for(int i=0;i<e;i++){rr[i+e] = rr[i];}for(int i=e*2;i<=2*n;i++)rr[i]=INF;for(int i=0; i<=e*2; i++){sa[i]=tmp[i]=i;tmp[i]=i;}
}int main()
{//freopen("poj 3581.txt","r",stdin);int p1,p2;scanf("%d",&n);mm=0;Init();con_sa(0,n);for(int i=0;i<=n;i++){p1=sa[i];if(p1>=2 && p1<n)break;}mm=1;Init2(p1);con_sa(0,p1*2);for(int i=0; i<=p1*2;i++){p2=sa[i];if(p2>=1 && p2<p1)break;}show(p1,p2);return 0;
}



这篇关于poj 3581 后缀数组 详解的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1009618

相关文章

Java中有什么工具可以进行代码反编译详解

《Java中有什么工具可以进行代码反编译详解》:本文主要介绍Java中有什么工具可以进行代码反编译的相关资,料,包括JD-GUI、CFR、Procyon、Fernflower、Javap、Byte... 目录1.JD-GUI2.CFR3.Procyon Decompiler4.Fernflower5.Jav

golang panic 函数用法示例详解

《golangpanic函数用法示例详解》在Go语言中,panic用于触发不可恢复的错误,终止函数执行并逐层向上触发defer,最终若未被recover捕获,程序会崩溃,recover用于在def... 目录1. panic 的作用2. 基本用法3. recover 的使用规则4. 错误处理建议5. 常见错

pycharm远程连接服务器运行pytorch的过程详解

《pycharm远程连接服务器运行pytorch的过程详解》:本文主要介绍在Linux环境下使用Anaconda管理不同版本的Python环境,并通过PyCharm远程连接服务器来运行PyTorc... 目录linux部署pytorch背景介绍Anaconda安装Linux安装pytorch虚拟环境安装cu

一文详解如何在Python中使用Requests库

《一文详解如何在Python中使用Requests库》:本文主要介绍如何在Python中使用Requests库的相关资料,Requests库是Python中常用的第三方库,用于简化HTTP请求的发... 目录前言1. 安装Requests库2. 发起GET请求3. 发送带有查询参数的GET请求4. 发起PO

Python进行PDF文件拆分的示例详解

《Python进行PDF文件拆分的示例详解》在日常生活中,我们常常会遇到大型的PDF文件,难以发送,将PDF拆分成多个小文件是一个实用的解决方案,下面我们就来看看如何使用Python实现PDF文件拆分... 目录使用工具将PDF按页数拆分将PDF的每一页拆分为单独的文件将PDF按指定页数拆分根据页码范围拆分

Java中的Cursor使用详解

《Java中的Cursor使用详解》本文介绍了Java中的Cursor接口及其在大数据集处理中的优势,包括逐行读取、分页处理、流控制、动态改变查询、并发控制和减少网络流量等,感兴趣的朋友一起看看吧... 最近看代码,有一段代码涉及到Cursor,感觉写法挺有意思的。注意是Cursor,而不是Consumer

SpringBoot项目注入 traceId 追踪整个请求的日志链路(过程详解)

《SpringBoot项目注入traceId追踪整个请求的日志链路(过程详解)》本文介绍了如何在单体SpringBoot项目中通过手动实现过滤器或拦截器来注入traceId,以追踪整个请求的日志链... SpringBoot项目注入 traceId 来追踪整个请求的日志链路,有了 traceId, 我们在排

HTML5中下拉框<select>标签的属性和样式详解

《HTML5中下拉框<select>标签的属性和样式详解》在HTML5中,下拉框(select标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中选择值的方式,本文将深入探讨select标签的... 在html5中,下拉框(<select>标签)作为表单的重要组成部分,为用户提供了一个从预定义选项中

Python中多线程和多进程的基本用法详解

《Python中多线程和多进程的基本用法详解》这篇文章介绍了Python中多线程和多进程的相关知识,包括并发编程的优势,多线程和多进程的概念、适用场景、示例代码,线程池和进程池的使用,以及如何选择合适... 目录引言一、并发编程的主要优势二、python的多线程(Threading)1. 什么是多线程?2.

Java 8 Stream filter流式过滤器详解

《Java8Streamfilter流式过滤器详解》本文介绍了Java8的StreamAPI中的filter方法,展示了如何使用lambda表达式根据条件过滤流式数据,通过实际代码示例,展示了f... 目录引言 一.Java 8 Stream 的过滤器(filter)二.Java 8 的 filter、fi