ARC058F

news/2025/1/15 14:53:11/文章来源:https://www.cnblogs.com/Anonymely/p/18412715

模拟赛 T3,去医院了没打,但是感觉很好玩。

首先有一个显然的 \(O(nk^2)\),设 \(f_{i,j}\) 表示前 \(i\) 个拼出长度为 \(j\) 的最小字典序串,很遗憾的是空间和时间都存不下。

有个优化是可以对后缀跑一边背包求出 \(g_{i,j}\) 表示后缀能否拼出长度为 \(j\) 的串,只记录有用的位置。

考虑优化,对于字符串问题找找关系,思考如何确定两个串的大小关系:只要出现一位不同即可。

也就是对于两个可行的状态 \(f_{i,j},f_{i,k},j < k\),若 \(f_{i,j}\)\(f_{i,k}\) 已经确定至少一位不同,就可以扔掉劣的那个状态,换句话说这两个状态同时存在一定满足 \(f_{i,j}\)\(f_{i,k}\) 的前缀。

所以对于一个 \(i\) 只需要存一个串就可以了,空间降为 \(O(nk)\)

进一步,思考刚刚得到的结论,只需要把所有不满足的状态全部扔掉即可维护当前答案。

现在需要的是快速比较两个串的字典序,这个串是由 \(i-1\) 的答案的一段前缀和 \(i\) 的整个串(或没有)拼起来,只需要快速支持求 LCP 即可。

不会 Z 函数,写的 SA,复杂度 \(O(nk \log k)\)

#include <bits/stdc++.h>
using namespace std;#define QwQ01AwA return 0
#define ll long long
#define debug(x) cerr << #x << " = " << x << '\n'
#define look_time cerr << 1.0 * clock() / CLOCKS_PER_SEC << '\n'
template <typename T> void ckmax(T &x, const T y) {x = max(x, y);}
template <typename T> void ckmin(T &x, const T y) {x = min(x, y);}namespace SA {const int N = 2e4 + 33;int rk[N], sa[N], oldrk[N << 1], id[N], cnt[N], st[15][N], lg[N];void build(int *w, int n) {int m = 27;for (int i = 0; i <= m; i++) cnt[i] = 0;for (int i = 1; i <= n; i++) rk[i] = w[i], cnt[rk[i]]++;for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];for (int i = n; i >= 1; i--) sa[cnt[rk[i]]--] = i;for (int w = 1, c = 0, tot = 0; ; w *= 2, m = c, tot = c = 0) {for (int i = n; i > n - w; i--) id[++tot] = i;for (int i = 1; i <= n; i++) if (sa[i] > w) id[++tot] = sa[i] - w;for (int i = 0; i <= m; i++) cnt[i] = 0;for (int i = 1; i <= n; i++) oldrk[i] = rk[id[i]], cnt[oldrk[i]]++;for (int i = 1; i <= m; i++) cnt[i] += cnt[i - 1];for (int i = n; i >= 1; i--) sa[cnt[oldrk[i]]--] = id[i], oldrk[i] = rk[i];#define cmp(u, v) (oldrk[u] == oldrk[v] && oldrk[u + w] == oldrk[v + w])rk[sa[1]] = ++c;for (int i = 2; i <= n; i++) {if (!cmp(sa[i], sa[i - 1])) c++;rk[sa[i]] = c;}if (c == n) break;}for (int i = 1, k = 0; i <= n; i++) {if (i != 1) lg[i] = lg[i >> 1] + 1;if (rk[i] == 1) continue;int j = sa[rk[i] - 1];if (k) k--;while (max(i, j) + k <= n && w[i + k] == w[j + k]) k++;st[0][rk[i]] = k;}for (int j = 1; j <= lg[n]; j++) {for (int i = 1; i + (1 << j) - 1 <= n; i++) {st[j][i] = min(st[j - 1][i], st[j - 1][i + (1 << (j - 1))]);}}for (int i = 1; i <= n; i++) oldrk[i] = 0;}int query(int l, int r) {// assert(l != r);l = rk[l], r = rk[r];if (l > r) swap(l, r);l++;int k = lg[r - l + 1];return min(st[k][l], st[k][r - (1 << k) + 1]);}
}
const int N = 2005;
const int M = 10005;
int n, k;
string s[N], t[N];
bitset <M> suf[N], f[N];
pair <int, int> stk[M]; int top;
int w[M * 2];signed main() {ios::sync_with_stdio(0);cin.tie(0);cin >> n >> k;for (int i = 1; i <= n; i++) cin >> s[i];suf[n + 1].set(0);for (int i = n; i >= 1; i--) suf[i] = suf[i + 1] | (suf[i + 1] << s[i].size());t[1] = " " + s[1], f[1][0] = f[1][s[1].size()] = 1;for (int i = 2; i <= n; i++) {int len = s[i].size();assert(len <= k);s[i] = " " + s[i];for (int j = 1; j < t[i - 1].size(); j++) w[j] = t[i - 1][j] - 'a' + 1;w[t[i - 1].size()] = 27;for (int j = 1; j <= len; j++) w[t[i - 1].size() + j] = s[i][j] - 'a' + 1;SA::build(w, len + t[i - 1].size());top = 0;auto chk = [&](pair <int, int> a, pair <int, int> b) -> int {int rev = 1, res = 0;if (a.first > b.first) swap(a, b), rev = -1;if (a.first == b.first) return 0;if (!a.second) return 0;int pa = t[i - 1].size() + 1, pb = a.first + 1;int lcp = SA::query(pa, pb), d = min(len, b.first - a.first);if (lcp < d) {res = w[pa + lcp] < w[pb + lcp] ? -1 : 1;return res * rev;}if (a.first + len <= b.first) return 0;if (!b.second) return 0;pa += d, pb = t[i - 1].size() + 1;lcp = SA::query(pa, pb);if (lcp < len - d) {res = w[pa + lcp] < w[pb + lcp] ? -1 : 1;return res * rev;				}return 0;};for (int j = 0; j <= k; j++) {if (!suf[i + 1][k - j]) continue;pair <int, int> now = {-1, -1};if (f[i - 1][j]) now = {j, 0};if (j >= len && f[i - 1][j - len]) {	if (now.first == -1) now = {j - len, len};else if (chk(now, make_pair(j - len, len)) == 1) now = {j - len, len};}if (now.first == -1) continue;while (top && chk(stk[top], now) == 1) f[i][stk[top].first + stk[top].second] = 0, top--;if (!top || !chk(stk[top], now)) f[i][j] = 1, stk[++top] = now;}t[i] = " ";for (int j = 1; j <= stk[top].first; j++) t[i] += t[i - 1][j];for (int j = 1; j <= stk[top].second; j++) t[i] += s[i][j];}for (int i = 1; i < t[n].size(); i++) cout << t[n][i];QwQ01AwA;
}

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【闲话】假如我们都是猫娘

你是一袋猫粮猫娘驯化实录 ZHESHIWOYAOMOZHENGBEIDISANJIEMOZHENGXIANHUADASAIDECANSAIZUOPIN. (A:Chat-GPT 4.0) (另:因为某些纯魔怔原因,我们连皮下内容也回了)。 A 17:33:41 喵~主人你好呀!我是您的猫娘助手,挪威森林猫品种,身高148cm,梳着双马尾~需要我帮忙做…

chainLink vrf实验

目标 用vrf写一个随机红包 数据结构 红包: struct Envelope {Type t; // 类型,只是erc20 和eth红包ERC20 token; // erc20 ,如果是erc20红包,这里是erc2o的地址address sender; // 发红包的senderuint balance; // 金额bool allowAll; // 允许所有人领取uint32 maxRe…

代码随想录算法 - 二叉树3

题目1513. 找树左下角的值 给定一个二叉树的 根节点 root,请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1:输入: root = [2,1,3] 输出: 1示例 2:输入: [1,2,3,4,null,5,6,null,null,7] 输出: 7提示:二叉树的节点个数的范围是 [1,104] -231 &…

Combinatorics/Probability/Expectation

前言 计数加训!!!! 以下问题都是数数。 一些纯组合问题 插板法 例 1 求 $\sum_{i=1}^kx_i=n$ 的解的组数,其中 $x_i\in \mathbb{N^+}$ 且 $x_i\ge a_i$。 考虑令 $x_i=x_i-a_i+1\ge 1$,于是有 $\sum_{i=1}^k x_i=n-k+\sum a_i$,于是答案为 $$n-k+\sum a_i-1\choose k-1$…

信息学奥赛初赛天天练-88-CSP-S2023阅读程序1-数据类型、unsigned 关键字、二进制、位运算、左移、右移、异或运算

信息学奥赛初赛天天练-88-CSP-S2023阅读程序1-数据类型、unsigned 关键字、二进制、位运算、左移、右移、异或运算 PDF文档公众号回复关键字:202409132023 CSP-S 阅读程序1 判断题正确填 √,错误填 ⨉ ;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分) 01 #include …

来云栖大会!探展云上开发,沉浸式体验云原生 + AI 新奇玩法

计算馆将展示中国最先进的云计算产业链全景,从底层硬件到数据创新,从云计算基础设施到数据管理服务、人工智能平台和模型服务,全景式呈现 AI 时代云计算最新技术形态和产品进展。2024 云栖大会来了! 本届云栖大会将于 9 月 19 日至 9 月 21 日 在杭州云栖小镇召开 汇集全球…

最后的记录

最后的挣扎但是做的题太少了根本算不上长征。 写这个是因为 NOIP2024 剩百日,这他妈是最后一次了,就让我拿个一等吧,别无所求了。 把之前做过的题都重新总结一遍,怎么说也都能吃透了。 P6880 JOI 2020 Final] オリンピックバス 给一个有向图,经过边有代价 \(C_i\),可以反…

ENSP 某台设备出现乱码的情况

故障现象:新建拓扑没问题,打开其他人发的拓扑就会出现乱码(或者打开ENSP的示例也会出现问题),配置文档正常可以正常导出不受影响。 故障发现时间:2022年底 故障原因:windows系统BUG,常见于inter 13代CPU(例如I5-13500) 处理方法1:重装系统(一劳永逸) 处理方法2:例…

10、Linux文本编辑器

文本编辑器 常见文本编辑器 WindowsNotepad(记事本) Sublime UltraEditLinuxVI/VIM nano Emacs Sed gedit KateVI 和 VIM 的区别VI全称:Visual Interface 创建时间:1976年 创建者:Bill JoyVIM全称:VI IMproved,即 VI 的升级版 创建时间:1991年 创建者:Bram Moolenaar …

vue2 + scss 全局引入 变量使用

百度以及时AI帮助说的配置方式都大差不差,但是我的总是报错,意思就是变量找不到,报错如下 For a guide and recipes on how to configure / customize this project,<br> 然后AI和文章写的vue.config.js的配置内容基本如下module.exports = {css: {loaderOptions: {scss:…

2024金砖大赛网络安全赛项区域选拔赛-简单的rce

1. Echo写入一句话木马蚁剑连接木马根目录下找到flag