当前位置: 首页 > news >正文

CF2165D Path Split 题解

Description

给定一个长度为 \(n\) 的整数序列 \(a_1, a_2, \ldots, a_n\)

你希望把 \(a\) 划分成若干个子序列 \(b_1, b_2, \ldots, b_k\),并满足以下条件:

  1. \(a\) 中的每个元素恰好属于某个 \(b_i\)
  2. 对于每个子序列 \(b_i\),设其元素为 \(b_{i,1}, b_{i,2}, \ldots, b_{i,p_i}\)。那么对所有 \(1 \le j < p_i\),都必须满足 \(|b_{i,j} - b_{i,j+1}| = 1\)

请计算,将 \(a\) 划分成满足条件的子序列所需的最小数量。

\(1\leq n\leq 10^6\)

Solution

首先这题是个典型的最小链覆盖的问题,考虑转成二分图最大匹配的形式:对于每个 \(i\),建立左部点 \(L_i\) 和右部点 \(R_i\)。如果 \(i<j\)\(|a_i-a_j|=1\),则让 \(L_i\)\(R_j\) 连边。答案是 \(n-最大匹配\)

直接跑匹配显然是不行的,考虑将其转化为贪心。

我们枚举左部点,考虑为每个左部点找到与其匹配的右部点。

由于左部点中值为 \(1\) 的只能匹配 \(2\),而 \(3\) 能匹配 \(2\)\(4\),所以 \(3\) 强于 \(1\),那么一定是先为 \(1\) 找到匹配,再为 \(3\) 找到匹配。

而对于左部点的 \(2\)\(4\) 情况会不太一样,因为 \(2\) 能匹配 \(1\)\(3\)\(4\) 能匹配 \(3\)\(5\),此时 \(2\) 不止能匹配 \(3\)。但是注意到如果存在一个 \(1\) 没有和 \(2\) 匹配,那么这个 \(1\) 就不能被匹配了。所以策略是对于每个 \(2\),如果能匹配 \(1\),就找到离它最近的 \(1\) 匹配,否则就找最近的 \(3\) 匹配。

最终策略就是从小到大枚举左部点的权值 \(v\),如果当前位置 \(x\) 能和值为 \(v-1\) 的右部点匹配,就找最近的 \(v-1\) 匹配,否则找最近的 \(v+1\) 匹配。

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

Code

#include <bits/stdc++.h>// #define int int64_tconst int kMaxN = 1e6 + 5;int n;
int a[kMaxN];
std::vector<int> pos[kMaxN * 2];
std::set<int> st[kMaxN * 2];void dickdreamer() {std::cin >> n;for (int i = 1; i <= 2 * n + 1; ++i) pos[i].clear(), st[i].clear();for (int i = 1; i <= n; ++i) std::cin >> a[i], pos[a[i]].emplace_back(i), st[a[i]].emplace(i);int ans = n;for (int i = 1; i <= 2 * n; ++i) {std::reverse(pos[i].begin(), pos[i].end());for (auto x : pos[i]) {auto it = st[i - 1].lower_bound(x);if (it != st[i - 1].end()) {--ans, st[i - 1].erase(it);} else {it = st[i + 1].lower_bound(x);if (it != st[i + 1].end()) --ans, st[i + 1].erase(it);}}}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.gsyq.cn/news/52400.html

相关文章:

  • 连续段 DP
  • 人工智能之编程基础 Python 入门:第八章 函数与装饰器
  • 邻项交换
  • 2025-11-17 ZYZ28-NOIP模拟赛-Round7 hetao1733837的record
  • markdown格式绘制各种图
  • 计算机网络第六章---应用层(基于谢希仁老师第八版)
  • 第一次接触 JSAPIThree(百度地图 JSAPI Three)学习笔记
  • vulkan学习笔记第一篇_环境部署
  • 25.11.17随笔联考总结
  • web代码模板
  • 2025-11-17 早报新闻
  • V8的浏览器运行时环境
  • http https
  • 使用 LLM + Atlassian MCP 1小时生成年终总结
  • 25.11.17
  • 在线升级
  • javascript类型
  • ftp工具linux
  • 2025年东莞厂房装修公司最新榜单:聚焦仓储物流厂房装修/恒温恒湿厂房装修定制化解决方案
  • 执行上下文
  • 版本号
  • 13. 安全上下文
  • JavaScript手写函数
  • 2025 最新冷库建造厂家推荐!医药 / 食品 / 物流 / 小型 / 大型 / 自动化冷库建造厂家企业品牌权威排行榜
  • 2025年南京高功率密度电源公司推荐,高功率密度电源/电源模块/军用电源/全国产化电源/氢能源车载直流转换器生产直销有哪些
  • 2025 最新推荐!保定篮球俱乐部培训中心实力榜单:揭秘行业顶尖机构服务与教学优势权威指南
  • exe文件在linux
  • CAD开发-AutoCAD Code Pack 封装包
  • 常见问题 --- Bad register number passed to arm.get register value
  • 2025 年最新制氮机厂家推荐排行榜:激光切割 / 防爆 / 化工等多场景精选,技术与服务双优指南金属加工制氮机/医药农业制氮机/SMT制氮机公司推荐