P5329 [SNOI2019] 字符串 题解

news/2024/9/25 10:26:00

Description

给出一个长度为 \(n\) 的由小写字母组成的字符串 \(a\),设其中第 \(i\) 个字符为 \(a_i\ (1\leq i\leq n)\)

设删掉第 \(i\) 个字符之后得到的字符串为 \(s_i\),请按照字典序对 \(s_1,s_2,……,s_n\) 从小到大排序。若两个字符串相等,则认为编号小的字符串字典序更小。

Solution

容易发现对于一个极长的字符相等的连续段删掉任何一个字符都是一样的,所以先把这些连续段缩掉。

然后从前往后扫,如果 \(s_i<s_{i+1}\),则 \(i\) 一定比 \([i+1,n]\) 的所有数字典序大,就放到末尾。否则 \(i\) 一定比 \([i+1,n]\) 的所有数字典序小,放到开头。

时间复杂度:\(O(n)\)

Code

#include <bits/stdc++.h>// #define int int64_tusing u64 = uint64_t;const int kMaxN = 1e5 + 5, kMaxL = 1e6 + 5, kMod = 1e9 + 7;int n;
int len[kMaxL], sum[kMaxL];
u64 pw[kMaxL];
std::string s[kMaxN];
std::vector<int> id[kMaxN], f[kMaxN];
std::vector<u64> hs[kMaxN];inline int add(int x, int y) { return (x + y >= kMod ? x + y - kMod : x + y); }
inline int sub(int x, int y) { return (x >= y ? x - y : x - y + kMod); }
inline void inc(int &x, int y) { (x += y) >= kMod ? x -= kMod : x; }
inline void dec(int &x, int y) { (x -= y) < 0 ? x += kMod : x; }void prework() {pw[0] = 1;for (int i = 1; i <= 1e6; ++i) pw[i] = 13331ull * pw[i - 1];for (int i = 1; i <= n; ++i) {hs[i].resize(len[i] + 1);for (int j = 1; j <= len[i]; ++j)hs[i][j] = 13331ull * hs[i][j - 1] + s[i][j];}
}int getpos(int x, int p) { // 去掉 p 后第 x 个字符的位置if (x < p) return x;else return x + 1;
}u64 gethash(std::vector<u64> &hs, int l, int r) {return hs[r] - hs[l - 1] * pw[r - l + 1];
}u64 gethash(std::vector<u64> &hs, int l, int r, int p) { // [l, r] 去掉 p 的哈希值if (p < l || p > r) return gethash(hs, l, r);else return gethash(hs, l, p - 1) * pw[r - p] + gethash(hs, p + 1, r);
}bool cmp(int a1, int b1, int a2, int b2) { // s[a1] 去掉 b1 位置的字符是否 <= s[a2] 去掉 b2 位置的字符int L = 0, R = std::min(len[a1] - 1, len[a2] - 1) + 1, res = 0;while (L + 1 < R) {int mid = (L + R) >> 1;if (gethash(hs[a1], 1, getpos(mid, b1), b1) == gethash(hs[a2], 1, getpos(mid, b2), b2)) L = res = mid;else R = mid;}if (res == std::min(len[a1] - 1, len[a2] - 1)) {if (res == len[a1] - 1) return 1;else return s[a1][getpos(res + 1, b1)] == '.';} else {return s[a1][getpos(res + 1, b1)] <= s[a2][getpos(res + 1, b2)];}
}void dickdreamer() {std::cin >> n;for (int i = 1; i <= n; ++i) {std::cin >> s[i];s[i] = " " + s[i] + ".";len[i] = (int)s[i].size() - 1;}prework();for (int i = 1; i <= n; ++i) {id[i].resize(len[i] + 1);int l = 1, r = len[i], lst = 0;for (int j = 1; j <= len[i] - 1; ++j) {if (s[i][j] < s[i][j + 1]) {for (int k = j; k >= lst + 1; --k) id[i][r--] = k;lst = j;} else if (s[i][j] > s[i][j + 1]) {for (int k = lst + 1; k <= j; ++k) id[i][l++] = k;lst = j;}}for (int j = lst + 1; j <= len[i]; ++j) id[i][l++] = j;}f[1].resize(len[1] + 1);for (int i = 1; i <= len[1]; ++i) f[1][i] = 1;for (int i = 2; i <= n; ++i) {f[i].resize(len[i] + 1);for (int j = 1; j <= len[i - 1]; ++j) sum[j] = add(sum[j - 1], f[i - 1][j]);int p = 0;for (int j = 1; j <= len[i]; ++j) {for (; p < len[i - 1] && cmp(i - 1, id[i - 1][p + 1], i, id[i][j]); ++p) {}f[i][j] = sum[p];}}int ans = 0;for (int i = 1; i <= len[n]; ++i) inc(ans, f[n][i]);std::cout << ans << '\n';
}int32_t main() {
#ifdef ORZXKRfreopen("in.txt", "r", stdin);freopen("out.txt", "w", stdout);
#endifstd::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);int T = 1;// std::cin >> T;while (T--) dickdreamer();// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ryyt.cn/news/64497.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

《鸿蒙/Harmony | 开发日志》预览文件

APP 中常有需求就是点击文件打开预览。 鸿蒙中,可以借助访问的预览文件服务来实现。 测试下来,常见的文档类型txt, doc, excel, ppt,pdf, 图片,视频等都是默认可以打开的。遇到不能打开的,界面也会按钮是否使用其他 APP 来打开。支持的文件类型 官方文档列出的支持类型,实…

redis-配置文件解读

Redis配置文件解读 第一节 网络配置相关 bind绑定连接IP 默认情况bind=127.0.0.1只能接受本机的访问请求,不写的情况下,无限制接受任何ip地址的访问,生产环境肯定要写你应用服务器的地址;服务器是需要远程访问的,所以需要将其注释掉.如果开启了protected-mode,那么在没有设…

Spring-MVC

Spring-MVC 介绍 https://docs.spring.io/spring-framework/reference/web/webmvc.html Spring Web MVC是基于Servlet API构建的原始Web框架,从一开始就包含在Spring Framework中。正式名称“Spring Web MVC”来自其源模块的名称( spring-webmvc ),但它通常被称为“Spring …

【泛微E9】查询部门的部门层级以及所有上级部门

效果图如下:field1:一级部门 field2:二级部门 field3:三级部门 field4:四级部门 field5:五级部门 field6:六级部门 创建视图,view_bmcjpath 视图定义如下: WITH RECURSIVE department_tree (id, DEPARTMENTMARK, supdepid, depth, path) AS ( -- 初始化查询(非递归部…

Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载

Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载Windows 10 on ARM, version 22H2 (updated Sep 2024) ARM64 AArch64 中文版、英文版下载 基于 ARM 的 Windows 10 请访问原文链接:https://sysin.org/blog/windows-10-arm/,查看最新版…

macOS 15 Blank OVF - macOS Sequoia 虚拟化解决方案

macOS 15 Blank OVF - macOS Sequoia 虚拟化解决方案macOS 15 Blank OVF - macOS Sequoia 虚拟化解决方案 适用于 VMware ESXi 和 VMware Workstation 的 macOS Sequoia 虚拟化模板 请访问原文链接:https://sysin.org/blog/macos-15-ovf/,查看最新版。原创作品,转载请保留出…

ArgoWorkflow教程(五)---Workflow 的多种触发模式:手动、定时任务与事件触发

上一篇我们分析了argo-workflow 中的 archive,包括 流水线GC、流水线归档、日志归档等功能。本篇主要分析 Workflow 中的几种触发方式,包括手动触发、定时触发、Event 事件触发等。1. 概述 Argo Workflows 的流水线有多种触发方式:手动触发:手动提交一个 Workflow,就会触发…

从零开始学机器学习——了解回归

在本文中,我们探讨了回归分析在统计学和数据分析中的重要性和应用。线性回归和逻辑回归作为两种主要的回归分析方法,分别适用于不同类型的数据建模和预测需求。通过数学建模,它们能够揭示变量之间的关系,并且在实际应用中展现了强大的预测能力。首先给大家介绍一个很好用的…