[CSP-S2024提高级T2]超速检测

题目链接

[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, \dots , p_m p1,p2,,pm 描述道路上所有测速仪的位置。

输出格式

对于每组数据:输出一行包含两个整数,第一个整数为所有测速仪都开启时被判定为超速的车辆数量,第二个整数为在不漏掉超速车辆的前提下最多可以关闭的测速仪数量。

输入输出样例 #1

输入 #1

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

输出 #1

3 3

说明/提示

【样例 1 解释】

在该组测试数据中,主干道长度为 15 15 15,限速为 3 3 3,在距离最南端 2 , 5 , 8 , 9 , 15 2, 5, 8, 9, 15 2,5,8,9,15 的位置各设有一个测速仪。

  • 第一辆车在最南端驶入,以 3 3 3 的速度匀速行驶。这辆车在整个路段上都没有超速。
  • 第二辆车在距离最南端 12 12 12 的位置驶入,以 4 4 4 的速度匀速行驶。在最北端驶离主干道时,它会被距离最南端 15 15 15 的测速仪判定为超速。
  • 第三辆车在距离最南端 1 1 1 的位置驶入,以 1 1 1 的初速度、 4 4 4 的加速度行驶。其在行驶了 3 2 − 1 2 2 × 4 = 1 \frac{3^2-1^2}{2\times 4}=1 2×43212=1 的距离,即到达 2 2 2 的位置时,速度变为 3 3 3,并在之后一直超速。因此这辆车会被除了距离最南端 2 2 2 的测速仪以外的其他测速仪判定为超速。
  • 第四辆车在距离最南端 5 5 5 的位置驶入,以 5 5 5 的初速度、 − 2 -2 2 的加速度行驶。其在行驶了 3 2 − 5 2 2 × ( − 2 ) \frac{3^2-5^2}{2\times (-2)} 2×(2)3252 的距离,即到达 9 9 9 的位置时,速度变为 3 3 3。因此这辆车在距离最南端 [ 5 , 9 ) [5, 9) [5,9) 时超速,会被距离最南端 5 5 5 8 8 8 的两个测速仪判定为超速。
  • 第五辆车在距离最南端 6 6 6 的位置驶入,以 4 4 4 的初速度、 − 4 −4 4 的加速度行驶。在其行驶了 3 2 − 4 2 2 × ( − 4 ) = 7 8 \frac{3^2-4^2}{2\times (-4)}=\frac{7}{8} 2×(4)3242=87 的距离后,即这辆车到达 6 7 8 6\frac{7}{8} 687 的位置时,其速度变为 3 3 3。因此这辆车在距离最南端 [ 6 , 6 7 8 ) [6,6\frac{7}{8}) [6,687) 时超速,但这段区间内没有测速仪,因此不会被判定为超速。

因此第二、三、四辆车会被判定为超速,输出的第一个数为 3 3 3

我们可以关闭距离最南端 2 , 8 , 9 2, 8, 9 2,8,9 的三个测速仪,保留 5 5 5 15 15 15 的两个测速仪,此时三辆之前被判定为超速的车依然被判定为超速。可以证明不存在更优方案,因此输出的第二个数为 3 3 3

【数据范围】

对于所有测试数据,保证:

  • 1 ≤ T ≤ 20 1 \leq T \leq 20 1T20
  • 1 ≤ n , m ≤ 1 0 5 1 \leq n, m \leq 10^5 1n,m105 1 ≤ L ≤ 1 0 6 1 \leq L \leq 10^6 1L106 1 ≤ V ≤ 1 0 3 1 \leq V \leq 10^3 1V103
  • 0 ≤ d i < L 0 \leq d_i < L 0di<L 1 ≤ v i ≤ 1 0 3 1 \leq v_i \leq 10^3 1vi103 ∣ a i ∣ ≤ 1 0 3 |a_i| \leq 10^3 ai103
  • 0 ≤ p 1 < p 2 < ⋯ < p m ≤ L 0 \leq p_1 < p_2 < \dots < p_m \leq L 0p1<p2<<pmL
测试点 n , m ≤ n,m\leq n,m特殊性质
1 1 1 10 10 10
2 2 2 20 20 20^
3 3 3 3000 3000 3000A
4 4 4 1 0 5 10^5 105^
5 5 5 3000 3000 3000B
6 6 6 1 0 5 10^5 105^
7 7 7 3000 3000 3000C
8 8 8 1 0 5 10^5 105^
9 9 9 3000 3000 3000
10 10 10 1 0 5 10^5 105^

特殊性质 A:保证 a i = 0 a_i = 0 ai=0

特殊性质 B:保证 a i > 0 a_i > 0 ai>0

特殊性质 C:保证 a i < 0 a_i < 0 ai<0,且所有车都不在最北端驶离主干道。

【提示】

与加速度有关的定义和公式如下:

  • 匀加速运动是指物体在运动过程中,加速度保持不变的运动,即每单位时间内速度的变化量是恒定的。
  • 当一辆车的初速度为 v 0 v_0 v0、加速度 a ≠ 0 a\neq 0 a=0,做匀加速运动,则 t t t 时刻后它的速度 v 1 = v 0 + a × t v_1 = v_0 + a \times t v1=v0+a×t,它的位移(即行驶路程) s = v 0 × t + 0.5 × a × t 2 s=v_0\times t+0.5\times a\times t^2 s=v0×t+0.5×a×t2
  • 当一辆车的初速度为 v 0 v_0 v0、加速度 a ≠ 0 a \neq 0 a=0,做匀加速运动,则当它的位移(即行驶路程)为 s s s 时,这辆车的瞬时速度为 v 0 2 + 2 × a × s \sqrt{v_0^2+2\times a\times s} v02+2×a×s
  • 当一辆车的初速度为 v 0 v_0 v0、加速度 a ≠ 0 a \neq 0 a=0,在它的位移(即行驶路程)为 v 1 2 − v 0 2 2 a \frac{v_1^2-v_0^2}{2a} 2av12v02 时,这辆车的瞬时速度为 v 1 v_1 v1

如果你使用浮点数进行计算,需要注意潜在的精度问题。

样例分析

主干道的长度为 15 15 15,有 5 5 5个测速仪,如下图所示:
在这里插入图片描述

  • 1 1 1辆车,从 0 0 0出发,初速度为 3 3 3,加速度为 0 0 0,不会超速
  • 2 2 2辆车,从 12 12 12出发,初速度为 4 4 4,加速度为 0 0 0,会被 15 15 15位置上的测速仪判定为超速,能判定超速的测速仪只有 { 5 } \{5\} {5}
  • 3 3 3辆车,从 1 1 1出发,初速度为 1 1 1,加速度为 4 4 4,行驶到 2 2 2位置加速到 3 3 3,会被 5 , 8 , 9 , 15 5,8,9,15 5,8,9,15位置上的测速仪判定为超速,能判定超速的测速仪有 { 2 , 3 , 4 , 5 } \{2,3,4,5\} {2,3,4,5}
  • 4 4 4辆车,从 5 5 5出发,初速度为 5 5 5,加速度为 − 2 -2 2,行驶到 9 9 9位置减速到 3 3 3,会被 5 , 8 5,8 5,8位置上的测速仪判定为超速,能判定超速的测速仪有 { 2 , 3 } \{2,3\} {2,3}
  • 5 5 5辆车,从 6 6 6出发,初速度为 4 4 4,加速度为 − 4 -4 4,行驶到 6 7 8 6\frac{7}{8} 687位置减速到 3 3 3,不会被任何测速仪判定为超速。

算法思想

通过样例分析可以发现,对于每一辆车:

  • 如果是匀速或者加速行驶(加速度 ≥ 0 \ge0 0),车辆在某个位置超过速度限制 V V V,那么这个位置后面的测速仪都会判定其超速。不妨设第 1 1 1个判定为超速的仪器编号为 l l l,那么区间 [ l , m ] [l, m] [l,m]的测速仪都可以判定超速。
    • 朴素的思想可以直接枚举 l l l。由于 l l l之后的测速仪都满足要求,具有二分性,因此可以二分答案来确定满足要求的最小 l l l
  • 如果是减速行驶(加速度 < 0 <0 <0),需要先找到车辆右边最近的测速仪 l l l,如果 l l l不能判定为超速,那么就不需要处理;否则,也可以通过二分答案找到能够判定其超速的仪器的最大编号 r r r,那么区间 [ l , r ] [l, r] [l,r]的测速仪都可以判定超速。

这样,对于每个被判定超速的车辆都会得到一个区间 [ l , r ] [l, r] [l,r],表示可以判定其超速的仪器的编号范围,区间的数量就是第一问的答案。

那么第二问就转化为区间选点问题,即选择尽量少的点,使得每个区间内至少包含一个选出的点。可以使用贪心来解决:

  • 首先,按照区间右端点从小到大排序
  • 遍历每个区间:
    • 如果当前区间覆盖了上一个选点位置,那么跳过该区间。
    • 否则,在该区间的最右边选择一个点

时间复杂度

  • 需要遍历 n n n辆汽车,通过二分查找满足条件的区间,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)
  • 对所有区间进行排序,然后贪心遍历每个区间,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

代码实现

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e5 + 5;
struct C
{
    int d, v, a;
}c[N];
struct Q
{
    int l, r;
}q[N];
int n, m, L, V, p[N];
bool check(int k, int i) //检查k位置的测速仪是否能拍到第i辆车超速
{
    if(k < c[i].d) return false; //测速仪无法拍到当前车辆
    int s = k - c[i].d; //行驶的距离
    return (long long) s * 2 * c[i].a + (long long) c[i].v * c[i].v > (long long) V * V; //行驶s后的瞬时速度超速了
}
int cmp(Q a, Q b)
{
    if(a.r != b.r) return a.r < b.r;
    else return a.l < b.l;
}
int main()
{
    int T;
    cin >> T;
    while(T --)
    {
        cin >> n >> m >> L >> V;
        for(int i = 1; i <= n; i ++) cin >> c[i].d >> c[i].v >> c[i].a;
        for(int i = 1; i <= m; i ++) cin >> p[i];
        int tot = 0;
        for(int i = 1; i <= n; i ++)
        {
            if(c[i].a >= 0) //匀速或者匀加速运动
            {
                int l = 1, r = m + 1;
                while(l < r) //二分查找能判定超速的测速仪的最小编号
                {
                    int mid = l + r >> 1;
                    if(check(p[mid], i)) r = mid;
                    else l = mid + 1;
                }
                if(l > m)  continue; //不存在测速仪
                else q[++ tot] = {l, m}; //p[l...m]的测速仪都可以判定第i辆车的超速
            }
            else
            {
                int l = 1, r = m + 1;
                while(l < r) //二分查找第一个大于等于当前车辆的位置
                {
                    int mid = l + r >> 1;
                    if(p[mid] >= c[i].d) r = mid;
                    else l = mid + 1;
                }
                if(!check(p[l], i)) continue; //l位置的测速仪不能判定超速
                int ql = l;
                r = m + 1;
                while(l < r) //二分查找能判定超速的测速仪的最大编号
                {
                    int mid = l + r + 1 >> 1;
                    if(check(p[mid], i)) l = mid;
                    else r = mid - 1;
                }
                q[++ tot] = {ql, l}; //p[l...m]的测速仪都可以判定第i辆车的超速
            }
        }
        sort(q + 1, q + tot + 1, cmp);
        int last = 0, ans = 0;
        for(int i = 1; i <= tot; i ++)
        {
            if(q[i].l <= last) continue;
            last = q[i].r;
            ans ++;
            
        }
		printf("%d %d\n", tot, m - ans); 
    }
}
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

少儿编程乔老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值