CF2001D Color Rows and Columns
题解
知识点:贪心,STL。
显然,子序列最长长度是数的种类数,即保证每个数都会被选到。子序列的奇数位要尽可能大、偶数位尽可能小。
我们从左到右依次选择子序列的数,为了保证每个数都能被选到,我们预处理出每个数的最晚出现位置 。每次选择,只有在当前还未选择的数的 的最小值之前(包括最小值位置),上一个选择位置之后(不包括上一个选择位置),并且还未被选择的数,是可以被选择的。这些可选数中,我们需要选择最大(最小)、位置靠前(给后面的数最多的被选机会)的数。
因此,我们要维护 值的大小顺序,并且支持删除,需要用一个 set<int>
维护。
同时,再用两个 set<pair<int,int>>
维护待选数的大小顺序、位置顺序。
每次选择之前,将位置在最小位置之前的数加入待选数集合,将在上一个选择位置之前的数都删除。注意,每次选择时,遍历待选数集合删除效率很低,因此我们只对选择时遇到的数判断是否删除,如此每个数只会判断一次。
在所有数都被选择过后,生成的序列即为答案。
时间复杂度
空间复杂度
代码
#include <bits/stdc++.h> using namespace std; using ll = long long; int a[300007], lst[300007]; bool solve() { int n; cin >> n; for (int i = 1;i <= n;i++) cin >> a[i], lst[a[i]] = i; set<int> st; for (int i = 1;i <= n;i++) if (lst[i]) st.insert(lst[i]); int pos = 1, pre = 0; set<pair<int, int>> st_min, st_max; vector<int> ans; while (st.size()) { while (pos <= *st.begin()) { if (lst[a[pos]]) { st_min.insert({ a[pos], pos }); st_max.insert({ -a[pos], pos }); } pos++; } while (!lst[st_min.begin()->first] || st_min.begin()->second <= pre) st_min.erase(st_min.begin()); while (!lst[-st_max.begin()->first] || st_max.begin()->second <= pre) st_max.erase(st_max.begin()); int val = ans.size() & 1 ? st_min.begin()->first : -st_max.begin()->first; pre = ans.size() & 1 ? st_min.begin()->second : st_max.begin()->second; ans.push_back(val); st.erase(lst[val]); lst[val] = 0; } cout << ans.size() << '\n'; for (auto val : ans) cout << val << ' '; cout << '\n'; return true; } int main() { std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << -1 << '\n'; } return 0; }
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/18427231
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧