欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
附上汇总贴:历年CSP-S复赛真题解析 | 汇总
【题目描述】
洛谷:P11232 [CSP-S 2024] 超速检测 - 洛谷
【题目描述】
小 D 新入职了某国的交管部门,他的第一个任务是负责国家的一条长度为 L L L 的南北主干道的车辆超速检测。为了考考小 D,上司首先需要他解决一个简化的场景。
这个周末,主干道上预计出现 n n n 辆车,其中第 i i i 辆车从主干道上距离最南端 d i d_i di 的位置驶入,以 v i v_i vi 的初速度和 a i a_i ai 的加速度做匀加速运动向北行驶。我们只考虑从南向北的车辆,故 v i > 0 v_i>0 vi>0,但 a i a_i ai 可正可负,也可以为零。当车辆行驶到主干道最北端(即距离最南端为 L L L 的位置)或速度降为 0 0 0(这只可能在 a i < 0 a_i<0 ai<0 时发生)时,我们认为该车驶离主干道。
主干道上设置了 m m m 个测速仪,其中第 j j j 个测速仪位于主干道上距离最南端 p j p_j pj 的位置,每个测速仪可以设置开启或关闭。当某辆车经过某个开启的测速仪时,若这辆车的瞬时速度超过了道路限速 V V V,那么这辆车就会被判定为超速。注意当车辆驶入与驶出主干道时,如果在对应位置有一个开启的测速仪,这个测速仪也会对这辆车进行测速。
上司首先想知道,如果所有测速仪都是开启的,那么这 n n n 辆车中会有多少辆车被判定为超速。
其次,为了节能,部门想关闭一部分测速仪。然而,他们不希望漏掉超速的车,也就是说,当 n n n 辆车里的某辆车在所有测速仪都开启时被判定为超速,他们希望在关闭一部分测速仪以后它依然被判定为超速。上司还想知道在这样的条件下最多可以关闭多少测速仪。
由于 n n n 很大,上司允许小 D 使用编程解决这两个问题,于是小 D 找到了你。
如果你对于加速度并不熟悉,小 D 贴心地在本题的“提示”部分提供了有关加速度的公式。
【输入】
输入的第一行包含一个正整数 T T T,表示数据组数。
接下来包含 T T T 组数据,每组数据的格式如下:
第一行包含四个整数 n , m , L , V n,m,L,V n,m,L,V,分别表示车辆数量、测速仪数量、主干道长度和道路限速。
接下来 n n n 行:
第 i i i 行包含三个整数 d i , v i , a i d_i,v_i,a_i di,vi,ai 描述一辆车。
最后一行包含 m m m 个整数 p 1 , p 2 , … , p m p_1,p_2,…,p_m p1,p2,…,pm 描述道路上所有测速仪的位置。
【输出】
对于每组数据:输出一行包含两个整数,第一个整数为所有测速仪都开启时被判定为超速的车辆数量,第二个整数为在不漏掉超速车辆的前提下最多可以关闭的测速仪数量。
【输入样例】
1
5 5 15 3
0 3 0
12 4 0
1 1 4
5 5 -2
6 4 -4
2 5 8 9 15
【输出样例】
3 3
【算法标签】
《洛谷 P11232 超速检测》 #模拟# #数学# #贪心# #二分# #排序# #CSP-S提高级# #2024# #O2优化#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 定义最大可能的数据范围
// 变量定义:
// n: 车辆数量
// m: 测速仪数量
// L: 道路长度
// V: 道路限速
// d[i]: 第i辆车的初始位置
// v[i]: 第i辆车的初始速度
// a[i]: 第i辆车的加速度
// p[i]: 第i个测速仪的位置
int n, m, L, V;
int d[N], v[N], a[N], p[N];
// 区间结构体,用于存储需要检测的区间
struct node
{
int l, r; // 区间的左右端点(测速仪编号)
};
// 比较函数,按区间右端点排序
bool cmp(node x, node y)
{
return x.r < y.r;
}
// 主处理函数
void solve()
{
// 输入数据
cin >> n >> m >> L >> V;
for (int i = 1; i <= n; i++)
cin >> d[i] >> v[i] >> a[i];
for (int i = 1; i <= m; i++)
cin >> p[i];
int cnt = 0; // 需要检测的区间数量
node b[N]; // 存储需要检测的区间
// 遍历所有车辆,确定需要检测的区间
for (int i = 1; i <= n; i++)
{
// 如果车辆初始速度不超速且加速度非正,则跳过
if (v[i] <= V && a[i] <= 0)
continue;
int l, r, x;
// 情况1:车辆初始速度已超速
if (v[i] > V)
{
// 找到第一个在车辆后方的测速仪
l = lower_bound(p + 1, p + m + 1, d[i]) - p;
if (a[i] >= 0)
{
// 如果加速度非负,则整个后方都需要检测
r = m;
}
else
{
// 计算减速到限速的位置
x = d[i] + (V * V - v[i] * v[i] + 1) / (2 * a[i]);
// 找到不超过该位置的最后一个测速仪
r = upper_bound(p + 1, p + m + 1, x) - p - 1;
}
}
// 情况2:车辆初始速度不超速但可能加速超速
else
{
// 计算加速到限速的位置
x = d[i] + (V * V - v[i] * v[i]) / (2 * a[i]);
// 找到超过该位置的第一个测速仪
l = upper_bound(p + 1, p + m + 1, x) - p;
r = m; // 直到最后一个测速仪
}
// 如果存在有效区间,则保存
if (l <= r)
b[++cnt] = {l, r};
}
// 按区间右端点排序
sort(b + 1, b + cnt + 1, cmp);
// 贪心算法选择最少的测速仪覆盖所有区间
int lst = 0, ans = 0; // lst: 上一个选择的测速仪,ans: 需要的最少测速仪数
for (int i = 1; i <= cnt; i++)
{
if (b[i].l > lst)
{ // 当前区间未被覆盖
++ans; // 选择当前区间的右端点
lst = b[i].r;
}
}
// 输出:需要检测的区间数量和最多可移除的测速仪数量
cout << cnt << " " << m - ans << endl;
}
int main()
{
int T; // 测试用例数量
cin >> T;
while (T--)
solve();
return 0;
}
【运行结果】
1
5 5 15 3
0 3 0
12 4 0
1 1 4
5 5 -2
6 4 -4
2 5 8 9 15
3 3