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

CSP-S 2024 超速检测 题解

CSP-S 2024 超速检测 题解

题目链接:CSP-S 2024 超速检测

题目简述

\(n\) 辆车,第 \(i\) 辆车初始位于 \(d_i\),速度为 \(v_i\),加速度为 \(a_i\)。道路范围为 \([0, L]\),有 \(m\) 个测速仪,位置分别为 \(p_1 < p_2 < \cdots < p_m\)。限速为 \(V\)

  • 第一问:有多少辆车会被至少一个测速仪检测到超速(即车辆经过测速仪时速度 \(> V\))?
  • 第二问:在保证仍能检测到所有超速车辆的前提下,最多可以关闭多少个测速仪?

算法思路

1. 物理模型 → 超速区间

对于第 \(i\) 辆车,运动学公式:

\(v^2 = v_i^2 + 2a_i (x - d_i)\)

其中 \(x\) 为车辆位置。要求 \(v > V\),即

\(v_i^2 + 2a_i (x - d_i) > V^2\)

整理得:

\(x > d_i + \frac{V^2 - v_i^2}{2a_i} \quad (a_i \neq 0)\)

由于测速仪位置是离散的,我们只需要知道车辆在哪些 连续位置区间 上会超速。设该区间为 \([l_i, r_i]\)(均为整数位置,包含边界)。

分类讨论:

  • \(v_i > V\):初始即超速。

    • \(a_i \ge 0\),速度不会减小,则从 \(d_i\)\(L\) 一直超速,即 \(l_i = d_i,\ r_i = L+1\)(用 \(L+1\) 表示无穷远)。
    • \(a_i < 0\),速度会逐渐减小,需要求出速度恰好降到 \(V\) 的位置 \(x_0\)
      \(x_0 = d_i + \frac{V^2 - v_i^2}{2a_i}\)
      因为 \(a_i < 0\),分母为负,\(x_0 < d_i\) 时可能不会降到限速以下?实际上,若初始超速且加速度为负,超速区间从 \(d_i\)\(\lfloor x_0 - 1 \rfloor\)(整数位置),代码中用整数防精度:
      \(r_i = d_i + \frac{v_i^2 - V^2 - 2a_i - 1}{-2a_i} - 1\)
      此处用整除向上取整的技巧,保证不出现浮点数。
  • \(v_i \le V\)

    • \(a_i \le 0\),速度不会增加,永远不会超速,\(l_i = r_i = L+1\)(空区间)。
    • \(a_i > 0\),速度会逐渐增加,超速从某个位置开始:
      \(x_0 = d_i + \frac{V^2 - v_i^2}{2a_i}\)
      则第一个超速的整数位置为 \(\lfloor x_0 \rfloor + 1\),即:
      \(l_i = d_i + \frac{V^2 - v_i^2}{2a_i} + 1\)
      之后一直超速到 \(L\)\(r_i = L+1\)

最终,每辆车对应一个超速区间 \([l_i, r_i]\)(闭区间),若 \(l_i > r_i\) 则无超速。


2. 判断是否被检测到

给定测速仪位置数组 \(p\),我们使用前缀和 pre[x] 表示位置 \(x\) 及以前有多少个测速仪。则区间 \([l, r]\) 内是否有测速仪,只需判断:

\(pre[r] - pre[l-1] > 0\)

若成立,说明该车会被至少一个测速仪拍到,计入第一问答案 cnta

同时,为了处理第二问,我们需要记录每个超速区间对应的“最右测速仪”。对于区间 \([l_i, r_i]\),利用二分查找 upper_bound(p+1, p+m+1, r_i) - p - 1 得到最后一个位置 \(\le r_i\) 的测速仪下标 pos。然后令:

\(arr[pos] = \max(arr[pos], l_i)\)

其中 arr[pos] 表示:若选择下标为 pos 的测速仪,它必须覆盖所有左端点 \(\ge arr[pos]\) 的区间(因为我们要让该测速仪尽可能向左覆盖,取最大左端点是最紧的要求)。


3. 贪心求最少保留测速仪

现在问题转化为:有若干个区间 \([l_i, r_i]\),每个区间已经绑定到其最右侧的测速仪 pos(即 \(p_{pos} \le r_i\)\(p_{pos}\) 是满足条件的最靠右的测速仪)。我们想要用尽量少的测速仪点覆盖所有区间,但这里测速仪只能选择这些离散点。

经典区间选点问题:按右端点排序,贪心选择右端点最小的区间的最右点。但代码采用从右向左的反向贪心,原理等价。

从右向左扫描测速仪下标 i(从 m2):

  • 当前测速仪 i 需要覆盖一些区间,这些区间的要求记录在 arr[i] 中(即这些区间的左端点最大值)。如果 arr[i] 有效(\(\ge 0\)),表示必须选点 i 才能覆盖这些区间。
  • 考虑左侧相邻的测速仪 i-1,位置为 \(p_{i-1}\)
    • \(p_{i-1} < arr[i]\),则左侧测速仪无法覆盖这些区间(因为 \(p_{i-1}\) 位于区间左端点左边),所以测速仪 i 必须保留。
    • 否则,左侧测速仪可以覆盖这些区间(因为 \(p_{i-1} \ge arr[i]\),且 \(p_{i-1} \le p_i \le r\),所以 \(p_{i-1}\) 一定在区间内),此时测速仪 i 可以被替代,我们将 arr[i] 的要求合并到 arr[i-1] 上:
      \(arr[i-1] = \max(arr[i-1], arr[i])\)
      并清空 arr[i](设为极小值)。

扫描结束后,所有 arr[i] \ge 0 的下标就是需要保留的测速仪数量 cntb。答案第二问为 m - cntb(可关闭的数量)。


代码实现细节

  • 使用 long long 避免乘法溢出。
  • 数组 pre 大小开至 M = 1e6+5,因为位置范围 \(0 \sim L\)
  • 计算区间时,全部使用整数运算,避免浮点数误差。
  • 区间端点 \(L+1\) 表示无限远,前缀和数组开到 \(L+2\)
  • arr 初始化为 -0x3f3f3f3f(极小值),代表无区间要求。
  • 二分查找使用 upper_bound,注意下标从 1 开始。

复杂度分析

  • 预处理每辆车:\(O(n)\)
  • 前缀和与差分:\(O(L + m)\)(实际 \(L\) 可能达 \(10^6\),可行)。
  • 每辆车二分查找最右测速仪:\(O(n \log m)\)
  • 扫描测速仪贪心:\(O(m)\)

总时间复杂度:\(O((n+m)\log m + L)\),空间复杂度:\(O(L + n + m)\)


完整代码(附注释)

#include <bits/stdc++.h>
#define int long long
using namespace std;const int N = 1e5 + 5, M = 1e6 + 5;int n, m, L, V;
int d[N], v[N], a[N], p[N];
int pre[M];          // 测速仪位置前缀和
int l[N], r[N];      // 每辆车的超速区间 [l, r]
int arr[N];          // arr[i]:测速仪 i 需要覆盖的最左端点
int cnta, cntb;signed main() {ios::sync_with_stdio(false);cin.tie(nullptr);int T;cin >> T;while (T--) {cin >> n >> m >> L >> V;memset(pre, 0, sizeof(pre));memset(arr, -0x3f, sizeof(arr));for (int i = 1; i <= n; i++) {cin >> d[i] >> v[i] >> a[i];}for (int i = 1; i <= m; i++) {cin >> p[i];pre[p[i]]++;}// 前缀和for (int i = 1; i <= L + 1; i++) {pre[i] += pre[i - 1];}// 计算每辆车的超速区间for (int i = 1; i <= n; i++) {if (v[i] > V) { // 初始超速l[i] = d[i];if (a[i] >= 0) { // 加速或匀速,一直超速r[i] = L + 1;} else { // 减速,计算降到 V 的位置int fs = d[i] + (v[i] * v[i] - V * V - 2 * a[i] - 1) / (-2 * a[i]);r[i] = min(L + 1ll, fs - 1);}continue;}// 初始不超速if (a[i] <= 0) { // 不会超速l[i] = r[i] = L + 1;continue;}// 加速,计算开始超速的位置int fs = d[i] + (V * V - v[i] * v[i]) / (2 * a[i]) + 1;l[i] = min(fs, L + 1ll);r[i] = L + 1;}cnta = cntb = 0;// 第一问 & 构建 arrfor (int i = 1; i <= n; i++) {if (l[i] > r[i]) continue;if (pre[r[i]] - pre[l[i] - 1] == 0) continue; // 区间内无测速仪cnta++; // 会被拍到// 找到区间内最靠右的测速仪下标int pos = upper_bound(p + 1, p + m + 1, r[i]) - p - 1;arr[pos] = max(arr[pos], l[i]);}// 贪心:从右向左合并for (int i = m; i >= 2; i--) {if (p[i - 1] < arr[i]) continue; // 左侧测速仪无法覆盖,保留当前// 可以合并arr[i - 1] = max(arr[i - 1], arr[i]);arr[i] = -0x3f3f3f3f; // 清空}for (int i = 1; i <= m; i++) {if (arr[i] >= 0) cntb++; // 需要保留的测速仪个数}cout << cnta << ' ' << m - cntb << '\n';}return 0;
}

总结

本题将物理运动学与经典的区间选点问题相结合,核心在于:

  1. 将超速条件转化为连续区间,并用整数运算避免精度问题。
  2. 利用前缀和快速判断区间内是否有测速仪
  3. 利用二分查找将区间绑定到最右侧的测速仪,再通过反向贪心求出最少保留数量。

本文由 AI 辅助整理

http://www.jsqmd.com/news/1378462/

相关文章:

  • 2026 年微信投票小程序推荐指南,多款主流平台对比测评
  • VSCode调试全攻略:launch.json与tasks.json配置详解与实战
  • AI Agent对话记忆管理:全量、摘要与向量策略的工业级选型指南
  • ViGEmBus虚拟游戏手柄驱动:终极Windows游戏控制器兼容性解决方案
  • 从零构建AI聊天助手:全栈开发实战与Cursor工具应用
  • 代码生成优化技术在嵌入式与AI部署中的应用
  • 从混乱项目标题到清晰理解:技术考古学实战指南
  • 四大主流消息队列深度对比:从架构设计到场景选型实战指南
  • 郑州靠谱犬舍怎么选?内行人认准这5个标准,轻松避开星期宠、串串宠 - 同城大型猫犬舍
  • QCMA:让你的PS Vita文件管理变得前所未有的简单
  • 河北保定干发帽厂家哪家靠谱?功能性面料选左右纺织品 - 优质新闻发布
  • K8s应用监控自动化:基于AI Agent Skill的智能接入实战
  • 如何通过本地化补丁技术重新定义游戏修改器体验:Wand-Enhancer深度技术解析
  • LangGraph实战:基于状态机与有向图构建多Agent智能编排系统
  • PyQt5安装全攻略:从原理到实战,彻底解决环境配置难题
  • 从RAG到上下文工程:大模型应用落地的核心技术解析与实践
  • 如何彻底解决Windows运行库问题:终极Visual C++运行库合集指南
  • LocalVocal:打造本地化实时字幕翻译的终极解决方案,让语音处理不再依赖云端
  • Ubuntu 22.04 生产环境部署Nacos:从单机模式到安全加固全指南
  • 本地操作型智能体深度测评:四类方案实战对比与选型指南
  • STM32 HAL工程模块化开发:Keil MDK文件夹创建与工程配置全攻略
  • 程序员副业复盘:2026年AI应用开发与云原生运维的实战机会
  • DDD分层架构实战:依赖倒置、防腐层与领域事件解耦指南
  • 四款AI视频笔记工具横向评测:Ai好记、通义听悟、Get笔记、听脑AI功能对比
  • Git命令实战指南:从场景化操作到高级问题排查
  • SpringBoot3+Vue3+MySQL 学分通智能化学分管理系统源码前后端分离实战
  • 华为与思科交换机生成树协议(STP)异构对接实战指南
  • Visual Studio中高效配置Eigen库:从原理到实战的完整指南
  • CPPM证书考试内容怎么咨询? - 众智商学院职业教育
  • 云原生核心技术解析:从微服务到Kubernetes的现代化应用架构实践