后缀数组(算法竞赛进阶指南 P64,字符串 Hash + 二分答案)

本文主要是介绍后缀数组(算法竞赛进阶指南 P64,字符串 Hash + 二分答案),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一.题目链接:

后缀数组

二.题目大意:

给字符串 s 的所有后缀按照字典序排序.

输出排序后的编号 和 排序后后缀数组 i 与 i - 1 的最大前缀长度.

三.分析:

如果直接用 sort 对每一个后缀排序,时间复杂度为 O(n^{2}logn),需要优化.

在 cmp 函数中,对于两个后缀 a,b 来讲,分别对应 s[a ~ n] 和 s[b ~ n].

那不妨求出第一个位置,使得 s[i] != s[j],\; 1\leq i < a < j \leq b.

这点可用字符串 Hash 前缀 + 二分答案实现.

这样每次只比较 1 个字符,排序函数的复杂度降到了 O(nlogn)

得到排序后的 SA 数组(记录编号)后,再同样二分前缀最大长度即可.

四.代码实现:

#include <set>
#include <map>
#include <ctime>
#include <queue>
#include <cmath>
#include <stack>
#include <bitset>
#include <vector>
#include <cstdio>
#include <sstream>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#define eps 1e-8
#define lc k * 2
#define rc k * 2 + 1
#define pi acos(-1.0)
#define ll long long
#define ull unsigned long long
using namespace std;const int M = (int)3e5;
const int mod = 99991;
const int inf = 0x3f3f3f3f;char s[M + 5];
int SA[M + 5];
ull P[M + 5];
ull sum[M + 5];int len;ull get_h(int l, int r)
{return sum[r] - sum[l - 1] * P[r - l + 1];
}int cal(int a, int b)
{int l = 0;int r = len - max(a, b) + 1;while(l < r){int mid = (l + r + 1) >> 1;if(get_h(a, a + mid - 1) == get_h(b, b + mid - 1))l = mid;elser = mid - 1;}return r;
}bool cmp(int a, int b)
{int x = cal(a, b);return s[a + x] < s[b + x];
}/**
ponoiiipoi
**/int main()
{scanf("%s", s + 1);len = strlen(s + 1);P[0] = 1;for(int i = 1; i <= len; ++i){SA[i] = i;P[i] = P[i - 1] * 131;sum[i] = sum[i - 1] * 131 + s[i] - 'a' + 1;}sort(SA + 1, SA + len + 1, cmp);for(int i = 1; i <= len; ++i)printf("%d%c", SA[i] - 1, i == len ? '\n' : ' ');for(int i = 1; i <= len; ++i)printf("%d%c", cal(SA[i - 1], SA[i]), i == len ? '\n' : ' ');return 0;
}

 

这篇关于后缀数组(算法竞赛进阶指南 P64,字符串 Hash + 二分答案)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

JAVA中整型数组、字符串数组、整型数和字符串 的创建与转换的方法

《JAVA中整型数组、字符串数组、整型数和字符串的创建与转换的方法》本文介绍了Java中字符串、字符数组和整型数组的创建方法,以及它们之间的转换方法,还详细讲解了字符串中的一些常用方法,如index... 目录一、字符串、字符数组和整型数组的创建1、字符串的创建方法1.1 通过引用字符数组来创建字符串1.2

使用JavaScript将PDF页面中的标注扁平化的操作指南

《使用JavaScript将PDF页面中的标注扁平化的操作指南》扁平化(flatten)操作可以将标注作为矢量图形包含在PDF页面的内容中,使其不可编辑,DynamsoftDocumentViewer... 目录使用Dynamsoft Document Viewer打开一个PDF文件并启用标注添加功能扁平化

Redis的Hash类型及相关命令小结

《Redis的Hash类型及相关命令小结》edisHash是一种数据结构,用于存储字段和值的映射关系,本文就来介绍一下Redis的Hash类型及相关命令小结,具有一定的参考价值,感兴趣的可以了解一下... 目录HSETHGETHEXISTSHDELHKEYSHVALSHGETALLHMGETHLENHSET

C#中字符串分割的多种方式

《C#中字符串分割的多种方式》在C#编程语言中,字符串处理是日常开发中不可或缺的一部分,字符串分割是处理文本数据时常用的操作,它允许我们将一个长字符串分解成多个子字符串,本文给大家介绍了C#中字符串分... 目录1. 使用 string.Split2. 使用正则表达式 (Regex.Split)3. 使用

电脑显示hdmi无信号怎么办? 电脑显示器无信号的终极解决指南

《电脑显示hdmi无信号怎么办?电脑显示器无信号的终极解决指南》HDMI无信号的问题却让人头疼不已,遇到这种情况该怎么办?针对这种情况,我们可以采取一系列步骤来逐一排查并解决问题,以下是详细的方法... 无论你是试图为笔记本电脑设置多个显示器还是使用外部显示器,都可能会弹出“无HDMI信号”错误。此消息可能

如何安装 Ubuntu 24.04 LTS 桌面版或服务器? Ubuntu安装指南

《如何安装Ubuntu24.04LTS桌面版或服务器?Ubuntu安装指南》对于我们程序员来说,有一个好用的操作系统、好的编程环境也是很重要,如何安装Ubuntu24.04LTS桌面... Ubuntu 24.04 LTS,代号 Noble NumBAT,于 2024 年 4 月 25 日正式发布,引入了众

vue如何监听对象或者数组某个属性的变化详解

《vue如何监听对象或者数组某个属性的变化详解》这篇文章主要给大家介绍了关于vue如何监听对象或者数组某个属性的变化,在Vue.js中可以通过watch监听属性变化并动态修改其他属性的值,watch通... 目录前言用watch监听深度监听使用计算属性watch和计算属性的区别在vue 3中使用watchE

Java中JSON字符串反序列化(动态泛型)

《Java中JSON字符串反序列化(动态泛型)》文章讨论了在定时任务中使用反射调用目标对象时处理动态参数的问题,通过将方法参数存储为JSON字符串并进行反序列化,可以实现动态调用,然而,这种方式容易导... 需求:定时任务扫描,反射调用目标对象,但是,方法的传参不是固定的。方案一:将方法参数存成jsON字

Spring Security 从入门到进阶系列教程

Spring Security 入门系列 《保护 Web 应用的安全》 《Spring-Security-入门(一):登录与退出》 《Spring-Security-入门(二):基于数据库验证》 《Spring-Security-入门(三):密码加密》 《Spring-Security-入门(四):自定义-Filter》 《Spring-Security-入门(五):在 Sprin

不懂推荐算法也能设计推荐系统

本文以商业化应用推荐为例,告诉我们不懂推荐算法的产品,也能从产品侧出发, 设计出一款不错的推荐系统。 相信很多新手产品,看到算法二字,多是懵圈的。 什么排序算法、最短路径等都是相对传统的算法(注:传统是指科班出身的产品都会接触过)。但对于推荐算法,多数产品对着网上搜到的资源,都会无从下手。特别当某些推荐算法 和 “AI”扯上关系后,更是加大了理解的难度。 但,不了解推荐算法,就无法做推荐系