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

【CF】Day51——Codeforces Round 963 (Div. 2) CD

C. Light Switches

题目:

思路:

思维+数学

我们首先肯定能找到一个规律,那就是开灯的时间戳是 a[i] + 2*k*x (x >= 0),且这是规律性的,那么最后的答案一定是在 max(a[i]) ~ max(a[i]) + k - 1 之间的,因为后面最晚亮的灯熄灭了,那么就要重新开始循环了,比如假设答案是 m,那么之后的答案也是 m + 2*k

那我们如何写呢?我们既然知道答案在其中,那么我们其实就可以将所有的 a[i] 全投影到 max(a[i]) ~ max(a[i]) + k - 1 之间,然后再排序一遍,如果最大值与最小值之差小于等于 k,那么就有答案,否则无解

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int n, k;cin >> n >> k;vector<int> a(n+1);for (int i = 1; i <= n; i++){cin >> a[i];}sort(a.begin() + 1, a.end());int MOD = 2 * k;for (int i = 1; i <= n; i++){a[i] += (a[n] + k - 1 - a[i]) / MOD * MOD;}sort(a.begin() + 1, a.end());if (a[n] - a[1] + 1 > k){cout << "-1\n";return;}cout << a[n] << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

D. Med-imize

题目:

思路:

经典中位数,还有似曾相识的二分+dp

首先我们要知道如何二分快速求中位数,我们假设中位数是 k,那我们可以令 a[i] >= k 的权值为 -1,而 a[i] < k 的权值为 1,那么最后只要权值之和 sum > 0 说明 k 是可以的

而上面这种方法的内核其实就是转换我们要求的东西,本题就是这种方式,我们可以二分最后的结果 mid,然后再判断是否符合,但是我们如何判断呢?

由于本体让我们要执行操作后的数组的长度小于等于 k,且我们每次都要删除连续 k 个数,那我们观察一下是否有什么规律?

我们可以将所有的下标模上k,我们可以发现我们每次删连续k个数都是删掉下标为 0 ~ k 的一个连续段,也就是说删掉后我们剩下的数组还是连续的,从结果来看,最后剩下的数组的下标肯定是 0 1 2 3 4 ... k (可能比k小),那这有什么用呢?

假如我们要保留第 1 个 0,那么下一个保留的 1 一定是在这个 0 的后面的,2 3 4...同理,也就是说我们可以用前一个数来推出后面的结果,那么我们就可以使用dp来解决这个问题

我们定义 dp[i] 为前 i 个元素中已经将数组删除到长度小于等于 k 时的权值之和,那么对于 dp[i] 我们有两种情况

如果 i % k == 0,也就是说这个点是 0,那我们就不能从上一个点直接转移过来,那我们就要新增一种保留的 0 的位置的情况,或者不新增(那就是继承之前的情况,由于是0,那么就要从0处转移过来),那么转移方程就是 dp[i] = max(dp[i - k],val)

否则对于不是 0 的元素,我们可以从前面这个元素直接转移过来,即dp[i] = dp[i - 1] + val,或者我们从之前的那个元素转移过来,即 dp[i] = d[i - k],二者取max即可,同时要注意特判 i > k

上诉dp转移最后的结果就是我们最后选择了下标为 0 ~ k(可能没有 k) 的元素各一个,然后其奉献和的值,判断也好判断了,即 dp[n - 1] > 0,最后二分经典操作即可

代码:

#include <iostream>
#include <algorithm>
#include<cstring>
#include<cctype>
#include<string>
#include <set>
#include <vector>
#include <cmath>
#include <queue>
#include <unordered_set>
#include <map>
#include <unordered_map>
#include <stack>
#include <memory>
using namespace std;
#define int long long
#define yes cout << "Yes\n"
#define no cout << "No\n"void solve()
{int n, k;cin >> n >> k;vector<int> a(n);for (int i = 0; i < n; i++){cin >> a[i];}auto check = [&](int mid) {vector<int> dp(n, 0);dp[0] = (a[0] >= mid ? 1 : -1);for (int i = 1; i < n; i++){if (i % k == 0){dp[i] = max(dp[i - k], (a[i] >= mid ? 1LL : -1LL));}else{dp[i] = dp[i - 1] + (a[i] >= mid ? 1LL : -1LL);if (i > k){dp[i] = max(dp[i], dp[i - k]);}}}return dp[n-1] > 0;};int l = 1, r = 1e9;while (l + 1 < r){int mid = l + r >> 1;if (check(mid)){l = mid;}else{r = mid;}}if (check(r)){cout << r << endl;return;}cout << l << endl;
}signed main()
{cin.tie(0)->sync_with_stdio(false);int t = 1;cin >> t;while (t--){solve();}return 0;
}

相关文章:

  • 【AI学习】DeepSeek-R1是如何训练的?
  • 我的世界Minecraft游戏服务器搭建教程:腾讯云Java版
  • 学习黑客Nmap 原理
  • 时间同步服务核心知识笔记:原理、配置
  • 【信息系统项目管理师-论文真题】2006下半年论文详解(包括解题思路和写作要点)
  • C# 检查某个点是否存在于圆扇区内(Check whether a point exists in circle sector or not)
  • 五大神经网络开发实战:从入门到企业级部署
  • 【数据结构与算法】同余计算 哈希表与前缀和问题特征和模板化思路
  • 滚珠螺杆的精度如何保持?
  • Nacos源码—3.Nacos集群高可用分析二
  • Vue中的过滤器参数:灵活处理文本格式化
  • Docker 使用下 (二)
  • 知识图谱 + 大语言模型:打造更聪明、更可靠的AI大脑 —— 探索 GraphRAG 中文优化与可视化实践
  • VirtualBox调整虚拟机内存和CPU
  • 数据库的原子事务
  • 阿里云物联网平台--云产品流传
  • Qt6.8中进行PDF文件读取和编辑
  • 【Java学习笔记】包
  • LeetCode 0790.多米诺和托米诺平铺:难想条件的简单动态规划
  • 实验-数字电路设计2-复用器和七段数码管(数字逻辑)
  • 48岁黄世芳履新中国驻毛里求斯大使,曾在广西工作多年
  • 伊朗公布新型弹道导弹,“萨德”系统无法拦截
  • 浙江医生举报3岁男童疑遭生父虐待,妇联:已跟爷爷奶奶回家
  • 云南省政协原党组成员、秘书长车志敏接受审查调查
  • 最火“五一”预订!小长假前两日多地接待游客量两位数增长,出境游订单井喷
  • 全国铁路昨日发送2311.9万人次,同比增长11.7%创历史新高