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

做题记录3

CF2149E. Hidden Knowledge of the Ancients

思路

滑动窗口 + 双指针。

先不考虑长度的限制,求"恰好有 \(k\) 个不同的数"的区间。可以维护两个窗口,一个是以当前的位置为右端点,且第一个最多有 \(k\) 个不同元素 的区间;一个是以当前位置为右端点,且第一个 最多有 \(k - 1\) 个不同元素 的区间。那么以当前位置为右端点,且恰好有 \(k\) 个不同元素的子区间的数量就为 最多 \(k - 1\) 个 - 最多 \(k\)。其实就是它们的左端点相减的结果。再加上长度限制,要满足

\[l \leq (右端点 - 左端点 + 1) \leq r \Rightarrow 右 - r + 1 \leq 左 \leq 右 - l + 1 \]

所以对于当前的右端点,合法的左端点的数量就为 \(\min(最多 k - 1 个的左端点, c - l + 1) - \max(最多 k 个的右端点, c - r + 1)\)

由于 \(a\) 的范围很大,所以要先离散化。

代码

void solve(void) {int n, k, l, r;std::cin >> n >> k >> l >> r;std::vector<int> a(n);for(int i = 0; i < n; i++) std::cin >> a[i];auto tmp = a;std::sort(tmp.begin(), tmp.end());tmp.erase(std::unique(tmp.begin(), tmp.end()), tmp.end());for(auto &i : a) {i = std::lower_bound(tmp.begin(), tmp.end(), i) - tmp.begin();}int len  = tmp.size();i64 ans = 0;std::vector<int> K(len), K1(len);int disk = 0, disk1 = 0;int lk = 0, lk1 = 0;for(int i = 0; i < n; i++) {K[a[i]]++;if(K[a[i]] == 1) {disk++;}while(disk > k) {int x = a[lk++];K[x]--;if(K[x] == 0) {disk--;}}K1[a[i]]++;if(K1[a[i]] == 1) {disk1++;}while(disk1 > k - 1) {int x = a[lk1++];K1[x]--;if(K1[x] == 0) {disk1--;}}int L = std::max(lk, i - r + 1);int R = std::min(lk1 - 1, i - l + 1);if(R >= L) ans += R - L + 1;}std::cout << ans << '\n';
}

CF2149F. Nezuko in the Clearing

思路

二分。

首先注意到,无论如何都是要走 \(d\) 个回合的,但是在这期间可能会休息若干次。因此可以表示为将 \(d\) 个回合分割为了 \(n\) 段,每段连续走 \(k_i\) 个回合,然后停下来休息一次,最后的答案就应该是:

\[d + (n - 1) \]

在这期间,血量的总消耗是:

\[\sum_{i = 1}^{n}\frac{k_i(k_i + 1)}{2} - (n - 1) \]

要保证消耗 \(\leq h - 1\) ,这样才能保证每一次触发的时候都有 \(\geq 1\) 的血量。

显然我们需要枚举分段的数量,如何 check 呢?

观察函数 \(f(k) = \frac{k(k + 1)}{2}\) ,我们想要让 \(\sum_{i = 1}^{n} f(k_i)\) 最小,注意到应该让每一段的长度都尽可能的接近,也就是说我们会分成若干段 \(\lfloor \frac{d}{n} \rfloor\) ,还有一段 \(d \mod n\) ,然后就可以判断了。

但是如何证明这个结论呢?我不会

代码

void solve(void) {i64 h, d;std::cin >> h >> d;if(h == 1) {std::cout << d * 2 << '\n';return;}i64 l = 1, r = d, len = -1;auto check = [&](i64 x) -> bool {i64 q = d / x;i64 r = d % x;i64 sum = r * (q + 1) * (q + 2) / 2;i64 sum1 = (x - r) * q * (q + 1) / 2;i64 total = sum + sum1 - (x - 1);return total <= h - 1;};while(l <= r) {i64 mid = (l + r) / 2;if(check(mid)) {r = mid - 1;len = mid;} else l = mid + 1;}//std::cout << len << '\n';std::cout << (len - 1) + d << '\n';
}
http://www.zskr.cn/news/11960.html

相关文章:

  • 2025年9月训练记录
  • 20250925 之所思 - 人生如梦
  • 在CodeBolcks下wxSmith的C++编程教程——在屏幕上绘图和保存绘图
  • 25.9.25
  • 每日博客(补)
  • 算法作业
  • C#学习3
  • 9-26
  • 2025.9.25总结 - A
  • Python建立ETF网格自动化交易集成动量阈值判断
  • 一文读懂Zookeeper与Kafka:从原理到实战部署 - 实践
  • Java 生态监控体系实战:Prometheus+Grafana+SkyWalking 整合全指南(三) - 教程
  • AC自动机在线版本(alert命中报警)
  • US$79 BMW FEM/BDC Key Programmer Data Desktop Test Platform for FEM/BDC Key and Program ECU Gearbox
  • (南科大深度学习课程笔记)Lecture_2_Mathematical background(数学背景)(上) - 详解
  • 页面卡顿问题分析与解决方案总结复盘
  • 实用指南:【FastMCP】中间件
  • Linux网络:运用UDP实现网络通信(网络套接字的创建绑定)
  • 常见进制
  • 大 LCP 时代(stupid.*)
  • 实用指南:Python实现手榴弹爆炸算法(Grenade Explosion Method, GEM)(附完整代码)
  • yolov10_float16.tflite TO yolov10_int8.tflite
  • Netty:完成RPC服务(实战)
  • 相交链表-leetcode
  • SQL Server从入门到项目实践(超值版)读书笔记 26 - 实践
  • 2025.9.25 sos dp小记
  • 我之软件工程观
  • vite+ts取别名@
  • day004
  • 软件测试团队准备解散了......