1.19 CW 赛时记录

news/2025/1/19 11:53:31/文章来源:https://www.cnblogs.com/YzaCsp/p/18679463

前言

听不懂了, 看到故人了

看题

\(\rm{T1}\)

串串
\(\rm{dp}\) , 做一下才知道

\(\rm{T2}\)

构构造造

困难

\(\rm{T3}\)

听不懂了

\(\rm{T4}\)

看不懂了


应该很困难
放平心态多打部分分

时间管控好, 然后就是做题

\(\rm{T1}\)

能不能给一个好一点的样例?

思路

首先转化题意

选出一堆人中的一个子集, 使得可以对这个子集进行排序, 满足不存在一个 \(j < i\) 使得 \(s_j > s_i\)\(s_j^r > s_i^r\) , 其中 \(>\) 表示字典序更大

抄了一遍题


因为可以对子集进行排序所以不好处理, 先找「不存在一个 \(j < i\) 使得 \(s_j > s_i\)\(s_j^r > s_i^r\)」的性质

因为字典序只在完全相同时才相等, 所以我们先按照 \(s_i\) 的字典序为第一关键字升序排序, 这样子所有可能的排序在原序列中都已经按序, 只是需要保证连续两个名字中必须恰有一个包含 m\(s_i^r\) 的约束

这里有一个误区是, 如果存在两个相同的 \(s_i\) 如何处理
你发现可能的排序在原序列中不一定按序, 但是我们可以把相同的串串合并处理
反正不影响答案

m 的约束好处理, 考虑 \(s_i^r\) 的约束
你发现在按照 \(s_i\) 的字典序为第一关键字升序排序之后, 我们可以知道每一个字符串按照 \(s_i^r\) 的字典序排序的编号, 容易知道只有递增选取才是合法的


好吧不太会做, 先暴力打满

\(\mathcal{O}(n^2)\)

这样方便用 \(\rm{dp}\) 处理
考虑令 \(dp_{i, j, 0/1}\) 表示当前考虑到了第 \(i\) 个位置, 之前选择的字符串, 其逆序排名最大为 \(j\) , 上一个位置是否包含 m , 最多选取的人数

这样每次转移就简单了

\[\begin{align*}\begin{cases}\textrm{case } \nexists \text{m} \in s_i , \begin{cases} dp_{i, j, 0} \gets dp_{i - 1, j, 0} \\ dp_{i, j, 1} \gets dp_{i - 1, j, 1} \\dp_{i, \textrm{order}_{s_i}, 0} \gets dp_{i - 1, k, 1} + 1 , k \leq \textrm{order}_{s_i} \\ \end{cases} \\\textrm{case } \exists \text{m} \in s_i , \begin{cases} dp_{i, j, 0} \gets dp_{i - 1, j, 0} \\ dp_{i, j, 1} \gets dp_{i - 1, j, 1} \\dp_{i, \textrm{order}_{s_i}, 1} \gets dp_{i - 1, k, 0} + 1 , k \leq \textrm{order}_{s_i} \\ \end{cases} \\\end{cases}\end{align*} \]

最终的答案即为 \(\max\limits_{j = 1}^{n} dp_{n, j, 0/1}\)

特殊性质 \(\rm{A}\)

这种情况下正反字符串字典序都按序, 直接 \(\rm{dp}\) 即可

正解

你发现 \(\mathcal{O} (n^2)\) 的转移, 只需要滚一维然后前缀和优化一下即可

前缀和并不好做, 考虑丢到线段树上去做
操作可以简化为

\(\textrm{case } \nexists \text{m} \in s_i\)

\(\textrm{order}_{s_i} , 0\) 位置替换成 \(1\) 中的前缀最大值 \(+1\) , 其他不变

\(\textrm{case } \exists \text{m} \in s_i\)

\(\textrm{order}_{s_i}, 1\) 位置替换成 \(0\) 中的前缀最大值 \(+1\) , 其他不变

也就是说, 我们开两个树状数组表示 \(01\) 位置的前缀最大值, 然后每次单点修改

实现

框架

按照上面的打即可

在这里造几组数据

6
abcmdef
acdef
bmbkkl
basd
jmzy
lssy

代码

#include <bits/stdc++.h>
// #define testcase
#define int long long
const int MAXN = 1e5 + 20;#define lowbit(x) ((x) & (-x))int n;
std::string name[MAXN], bin[MAXN];
std::unordered_map<std::string, int> order; // 逆序排名 ∈ [1, n]
std::unordered_map<std::string, bool> have; // 是否带有 mvoid init() {for (int i = 1; i <= n; i++) {std::cin >> name[i];for (int j = 0; j < name[i].length(); j++) {if (name[i][j] == 'm') have[name[i]] = true;bin[i] += name[i][name[i].length() - j - 1];}}std::sort(bin + 1, bin + n + 1);std::sort(name + 1, name + n + 1);int cnt = std::unique(bin + 1, bin + n + 1) - (bin + 1);for (int i = 1; i <= cnt; i++) {std::string ret = "";for (int j = 0; j < bin[i].length(); j++) ret += bin[i][bin[i].length() - j - 1];order[ret] = i;}
}class BIT
{
private:int tree[MAXN << 1]; // 保险一点public:/*初始化*/ void init() { memset(tree, 0, sizeof tree); }/*单点修改*/ void update(int x, int d) { while (x <= n) tree[x] = std::max(tree[x], d), x += lowbit(x); }/*前缀最大值*/ int query(int x) { int ans = 0; while (x > 0) ans = std::max(tree[x], ans), x -= lowbit(x); return ans; }} p0, p1;void solve() {p0.init(), p1.init();for (int i = 1; i <= n; i++) {if (have[name[i]]) {int p = order[name[i]];p1.update(p, p0.query(p) + 1);} else {int p = order[name[i]];p0.update(p, p1.query(p) + 1);}}int ans = std::max(p0.query(n), p1.query(n));printf("%lld", ans);
}signed main()
{
#ifdef testcasefreopen("queue_ex.in", "r", stdin);freopen("myans.out", "w", stdout);
#endifscanf("%lld", &n);init();solve();return 0;
}

常数太大, 不知道会卡掉多少分

\(\rm{map}\) 改了快了不少, 丢了
虽然还是有点悬, 应该 \(2000 \ \rm{ms}\) 过得去, 吧

\(\rm{T2}\)

有点慌, 先看这个
又一次简单题想半天, 归根结底还是太菜了, 你说我还给别人说是读错题了是不是有点小丑, 哎哎

这题肯定是暴力, 或者说因为时间, 后面的肯定都是暴力

思路

特殊性质 \(\rm{A}\)

这种情况下, \(s [n - i + 1 : n]\) 的排名是 \(i\) , 也就是说其字典序第 \(i\)

这是一个非常明显的性质, 也就是说后缀的字典序单调递增
怎么利用, 你发现「后缀的字典序单调递增」保证了最后字符串中, 字母按照字典序从大到小排序

这个时候再去考虑 \(b\) 数组
在这个性质下, \(b\) 数组相当于约束了任意两个相邻后缀的最长公共子前缀

考虑怎么按照 \(b\) 数组去构造
对于每一个 \(s [i : n] , s [i + 1 : n]\) 的约束, 你标记它应该在哪里断开, 然后最后填上数即可

这里给出一组样例

11
11 10 9 8 7 6 5 4 3 2 1
-1 -1 2 -1 0 -1 -1 -1 2 -1 -1zzzzzyyxxxxx
class subtask2
{
private:bool flag[MAXN];public:void Main() {memset(flag, false, sizeof flag);for (int i = 2; i <= n; i++) {if (b[i] == -1) continue;int x = a[i - 1], y = a[i];flag[x + b[i]] = true;}int now = 0;char str[MAXN];for (int i = n; i >= 1; i--) {if (flag[i]) now++;str[i] = (now + 'a');}for (int i = 1; i <= n; i++) std::cout << str[i];}} sub2;

特殊性质 \(\rm{B}\)

这个约束很强, 没时间想了

暴力

枚举判断即可

/*纯暴力*/
class subtask1
{
private:std::string ans = "zzzzzz";bool check(std::string str) {std::string suf[10];suf[n + 1] = "";for (int i = n; i >= 1; i--) suf[i] = str[i] + suf[i + 1];std::sort(suf + 1, suf + n + 1);for (int i = 1; i <= n; i++) if (a[n - suf[i].length() + 1] != i) return false;suf[n + 1] = "";for (int i = n; i >= 1; i--) suf[i] = str[i] + suf[i + 1];for (int i = 2; i <= n; i++) {if (b[i] == -1) continue;int x = a[i - 1], y = a[i];std::string sx = suf[x], sy = suf[y];int lsy = 0;for (int j = 0; j < sy.length(); j++) {if (sx[j] == sy[j]) lsy++;else break;}if (lsy != b[i]) return false;}return true;}void dfs(int now, std::string str) {if (now == n + 1) {if (check(str)) {ans = std::min(ans, str);return;} else {return;}}for (int i = 0; i < 26; i++) {dfs(now + 1, str + (char)(i + 'a'));}}public:void Main() {dfs(1, " ");for (int i = 1; i <= n; i++) std::cout << ans[i];}
} sub1;

要被卡成 \(0\)

\(\rm{T3}\)

直接打送的 \(40 \ \rm{pts}\)

总结

继续每日一练, 复习

策略没问题, 注重马力锻炼

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

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

相关文章

.NET周刊【1月第1期 2025-01-05】

国内文章 3款.NET开源、功能强大的通讯调试工具,效率提升利器! https://www.cnblogs.com/Can-daydayup/p/18631410 本文介绍了三款功能强大的.NET开源通讯调试工具,旨在提高调试效率。这些工具包括LLCOM,提供串口调试和自动化处理功能;Wu.CommTool,支持Modbus RTU和MQTT调…

Servlet 详解!

一、Servlet简介 Servlet是Sun公司开发动态Web的一门技术。Sun公司在这些API中提供了一个Servlet接口,如果你想开发一个Servlet程序只需要完成如下两个步骤: 1、编写一个Java类实现Servlet接口。 2、把开发好的Java类部署到Web服务器中。 我们把实现了Servlet接口的Java程序叫…

图论/连通性

点边连通度:耳分解: 强连通有向图/边双联通无向图 从一个点出发,每次加入从集合出发回到集合,中间点不在集合内的环,一定能生成该图。 边双 强连通 双极定向:link 割空间与环空间互为正交补。 切边等价:模板 qoj1351CF1648F 树分解:也就是找到一种划分方式,使得每种划…

比特c语言-分支与循环

# 分支与循环 if语句 目录if语句ifeg:输入一个整数,判断是否为奇数elseeg:输入一个整数,判断是否为奇数,如果是奇数打印是奇数,否则打印偶数嵌套ifeg:输入一个人的年龄关系操作符条件操作符eg:使用条件操作符表示代码逻辑eg:使用条件表达式找两个数中较大值逻辑操作符…

NOIP 冲刺之——数据结构

\(\texttt{0x00}\) 前言 本篇文章主要记录笔者 NOIP 冲刺阶段复习的各种数据结构题型及 tricks ans tips,同时也用于及时复习与巩固。 那么,开始吧。 \(\texttt{0x01}\) 树状数组、线段树 知识点 \(1\):二维偏序 众所周知,逆序对可以用归并排序离线求,但是要求在线呢? 这…

windows 将docker desktop上镜像打包并通过资源管理器找到使用

在 Windows 上使用 Docker Desktop 时,可以通过以下步骤将 Docker 镜像保存为 .tar 文件,并通过资源管理器找到该文件:步骤 1:打开 Docker Desktop 确保 Docker Desktop 正在运行。如果未运行,请启动它。步骤 2:打开 PowerShell 或命令提示符按 Win + S,搜索 PowerShell…

解决方案 | office365/office 修复方法

打开控制面板,选择卸载程序,右键office 一般情况下,选择快速修复可以实现修复。如不行,那么选择联机修复‘。还是不行那就重装office

【pywinauto 库】启动PC端应用程序 - 上篇

一、简介 经过上一篇的学习、介绍和了解,想必小伙伴或者童鞋们,已经见识到pywinauto的强大了,今天继续介绍pywinauto,上一篇已经可以打开计算器了,这里宏哥再提供其他方法进行打开计算器和非电脑自带程序。pywinauto 可以启动电脑自带的应用程序,也可以启动电脑安装的应用…

【反EDR 】概要

一、什么是 EDR EDR 是“端点检测和响应”的缩写。它是部署在每台机器上的代理,用于观察操作系统生成的事件以识别攻击。如果检测到某些东西,它将生成警报并将其发送到 SIEM 或 SOAR,由人工分析师进行查看。“响应”是指在识别威胁后执行的操作,例如隔离主机,这不是本文的…

USB接口颜色都代表什么含义

手机充电器人人都有!充电器线颜色都不同!你知道不同颜色的USB接口的各个颜色都代表什么含义吗?大部分人都是不知道的,这篇文章让您 一目了然!建议收藏备用!以备不时之需!

Windows资源管理器Icon图标注入

免责声明 本文发布的工具和脚本,仅用作测试和学习研究,禁止用于商业用途,不能保证其合法性,准确性,完整性和有效性,请根据情况自行判断。简介 使用图标将 DLL 注入资源管理器的非正统和隐蔽方式 IconJector 这是一个Windows资源管理器DLL注入技术,使用Windows上的更改图…

ElasticSearch Query DSL(查询领域特定语言)

目录常用 DSL 关键字查询上下文相关度评分:_score源数据:_source数据源过滤器query 和 filter 上下文相关性评分 (relevance scores)query 的上下文filter 的上下文关于 query 和 filter 上下文的例子全文查询 (full text query)intervals 查询请求示例intervals的顶级参数ma…