【巧用set实现对有序数组O(logn)时间复杂度增、删、查、改、二分操作】codeforces 1041 C. Coffee Break
题意
第一行输入三个整数 \(n,m,d(1 \leq n \leq 2 * 10^5, n \leq m \leq 10^9, 1 \leq d \leq n)\),第二行输入 \(n\) 个整数,保证每个数均不大于 \(m\)。
在每一天你都可以任意选择一个未选过的数 \(a_i\),随后可以继续选任意一个大于 \(a_i + d\) 的数 \(a_j\);接下来可以再选任意一个大于 \(a_j + d\) 的数 \(a_k\);最后重复执行上述步骤。
问:最少需要多少天,可以选完全部的数?
题解
先给结论:先从小到大排序,然后选中剩下的数组的第一个数 \(a_0\),随后选中数组中第一个满足 \(a_i \geq a_0 + d + 1\) 的数 \(a_i\),下一步再选中数组中第一个满足 \(a_j \geq a_i + d\) 的数 \(a_j\),形成的子数组数目便是答案。
疑问解析:为什么优先选择最小的满足 \(a_j \geq a_i + d + 1\)的数是正确的?
答:不妨假设数组排序后为 \(a_0, a_1, ..., a_i, a_j, ..., a_n\),且 \(a_i\) 是最小的满足大于 \(a_0 + d\) 的数。那么明显在选中 \(a_0\) 的下一步,既可以选择 \(a_i\),也可以选择 \(a_j\)。此时若 \(a_j - a_i \leq d\),那明显二者至多只能够选其一,那么无论选择哪一个,都必然意味着需要另外再选择出一个子数组。但如果 \(a_j - a_i \geq d + 1\),就可以先选 \(a_i\) 而后一并选上 \(a_j\)。因此,先选较小者更优。
接下来分析具体代码实现:
如何在数组中找出第一个比选中的数大 \(d\) 以上的数呢?
明显可以线性查找,但是当数组中任意两个数的差值均小于 \(d\) 时,时间复杂度为 \(O(n^2)\),明显不符合要求
观察我们的前置条件排序,所以可以考虑使用二分法来使得查找的时间复杂度降低为 \(O(logn)\)
如何选择过的数从数组中移除呢?
若通过类似插入排序等思路,时间复杂度为 \(O(n^2)\),明显不符合要求
此时思考:既要排序,又要可以二分,还要支持快速删除,我们可以联想到红黑树的性质,但是手撕红黑树太硬核了,可以借助 \(set\) 或 \(map\) 实现,这二者的查找/插入/删除/修改操作时间复杂度都是 \(O(logn)\),符合时间复杂度要求。
参考代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;
constexpr int INF = 0x3f3f3f3f;
constexpr int N = 2e5 + 7;
int n, m, d, cnt, a;
int ans[N];
int main() {
IOS
set<PII> st;
cin >> n >> m >> d;
for (int i = 0; i < n; ++ i) {
cin >> a;
st.insert(PII(a, i));
}
while (!st.empty()) {
auto f = st.begin();
int key = (*f).first;
ans[(*f).second] = ++ cnt;
st.erase(f);
while (!st.empty()) {
auto ne = st.upper_bound(PII(key + d, INF));
if (ne != st.end()) {
key = (*ne).first;
ans[(*ne).second] = cnt;
st.erase(ne);
} else break;
}
}
cout << cnt << '\n';
for (int i = 0; i < n; ++ i) cout << ans[i] << ' ';
return 0;
}
【巧用set实现对有序数组O(logn)时间复杂度增、删、查、改、二分操作】codeforces 1041 C. Coffee Break的更多相关文章
- [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)
题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...
- iOS常用算法之两个有序数组合并, 要求时间复杂度为0(n)
思路: 常规思路: 先将一个数组作为合并后的数组, 然后遍历第二个数组的每项元素, 一一对比, 直到找到合适的, 就插入进去; 简单思路: 设置数组C, 对比A和B数组的首项元素, 找到最小的, 就放 ...
- 使用C语言封装数组,动态实现增删改查
myArray.h : #pragma once //包含的时候只包含一次 #include <stdio.h> #include <stdlib.h> #include &l ...
- 【算法】字典的诞生:有序数组 PK 无序链表
参考资料 <算法(java)> — — Robert Sedgewick, Kevin Wayne <数据结构> ...
- 两个有序数组的上中位数和第K小数问题
哈,再介绍个操蛋的问题.当然,网上有很多解答,但是能让你完全看懂的不多,即便它的结果是正确的,可是解释上也是有问题的. 所以,为了以示正听,我也做了分析和demo,只要你愿意学习,你就一定能学会,并且 ...
- 【算法】实现字典API:有序数组和无序链表
参考资料 <算法(java)> — — Robert Sedgewick, Kevin Wayne <数据结构> ...
- [LeetCode] Find Minimum in Rotated Sorted Array 寻找旋转有序数组的最小值
Suppose a sorted array is rotated at some pivot unknown to you beforehand. (i.e., 0 1 2 4 5 6 7 migh ...
- [LeetCode] Convert Sorted Array to Binary Search Tree 将有序数组转为二叉搜索树
Given an array where elements are sorted in ascending order, convert it to a height balanced BST. 这道 ...
- [LeetCode] Merge Sorted Array 混合插入有序数组
Given two sorted integer arrays A and B, merge B into A as one sorted array. Note:You may assume tha ...
- [LeetCode] Remove Duplicates from Sorted Array 有序数组中去除重复项
Given a sorted array, remove the duplicates in place such that each element appear only once and ret ...
随机推荐
- MySQL精品学习资源合集 | 含学习教程笔记、运维技巧、图书推荐
MySQL凭借开源.免费.低门槛.稳定等优势,成为了当前最流行的关系型数据库之一.从1998年发行第一版以来,通过不断地更新迭代,MySQL被越来越多的公司使用,已然成为当下潮流. 为了帮助大家更好地 ...
- 什么是 RBAC 权限控制
RBAC是Role Based Access Control的英文缩写,意思是 基于角色的访问控制. RBAC实际上就是针对产品去挖掘需求时所用到的Who(角色).What(拥有什么资源).How(有 ...
- Windows刷机-记录UltraSO工具安装错误
安装镜像刻录U盘工具UltralSO:UltraISO - ISO CD/DVD image creator, editor, burner, converter and virtual CD/DVD ...
- 蜘点云原生之 KubeSphere 落地实践过程
作者:池晓东,蜘点商业网络服务有限公司技术总监,从事软件开发设计 10 多年,喜欢研究各类新技术,分享技术. 来源:本文由 11 月 25 日广州站 meetup 中讲师池晓东整理,整理于该活动中池老 ...
- LiveData
ViewModel 添加依赖 implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' activity_main.xml < ...
- 避免大量ifelse(枚举、工厂模式、策略模式)
枚举 public class Test { public static void main(String[] args) { System.out.println(judge("ROLE_ ...
- OKR 目标和关键成果
OKR(Objectives and Key Results)是目标与关键成果管理法,是一套明确和跟踪目标及其完成情况的管理工具和方法.1.OKR首先是沟通工具:团队中的每个人都要写OKR,所有这些O ...
- 关于 PyCharm 2024安装使用 (附加永久激活码、补丁)
第一步:下载安装包 访问 IDEA 官网,下载安装包,下载链接如下 : https://www.jetbrains.com.cn/pycharm/ 第二步,安装完成之后,下载补丁 下载地址(里面包含激 ...
- pdf.js使用
百度上很多例子,都是构建之前的! 我们使用pdf.js,最终只需要构建后的内容,大家可以通过这里进行下载: https://pan.baidu.com/s/14J-m-jeHdvn46cPhPXk54 ...
- Flink RetractStream示例及UDF函数实现
介绍 今天在Flink 1.7.2版本上跑一个Flink SQL 示例 RetractPvUvSQL,报 Exception in thread "main" org.apache ...