[luoguP11232/CSP-S2024] 超速检测

题意

给定数轴,终点为 \(L\)\(n\) 个动点做向右匀变速或匀速运动,求有多少个动点在经过任意给定检测点时瞬时速度严格大于 \(V\),以及最多删除多少个检测点能使得第一问的答案不变。

sol

第一问

按照加速度的正负分类讨论,套公式计算即可。需要注意是严格大于,因此需要考虑区间断点的开闭问题,解决方案为开区间增减 \(eps\)
本题有题面诈骗,并不会炸精度。

第二问

典贪心(但是我考场上没做出来,我太菜了呜呜呜)
排序后将右端点放入单调栈(或堆)中,删除包含了其他区间的区间(这样的区间会影响后面贪心的答案,且一定不会有更多贡献),然后双指针取能取的最右点即可。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>

#define x first
#define y second 
using namespace std;
typedef pair<int, int> PII;

const int N = 100005;
const double eps = 1e-6;

int n, m, l, V;
int T;
double p[N];
int d[N], v[N], a[N];
PII ranges[N], new_ranges[N];
int idx;
bool st[N];

int main(){
    // freopen("detect.in", "r", stdin);
    // freopen("a.out", "w", stdout);
    scanf("%d", &T);
    while (T -- ){
        scanf("%d%d%d%d", &n, &m, &l, &V);
        for (int i = 1; i <= n; i ++ ){
            scanf("%d%d%d", &d[i], &v[i], &a[i]);
        }

        for (int i = 1; i <= m; i ++ ) scanf("%lf", &p[i]);

        int cnt = 0;
        for (int i = 1; i <= n; i ++ ){
            PII range;
            if (a[i] == 0) {
                if (v[i] <= V) range = {0, -1};
                else {
                    int ll = lower_bound(p + 1, p + m + 1, d[i]) - p;
                    range = {ll, m};
                }
            }
            else if (a[i] > 0) {
                double lpos;
                if (v[i] > V) lpos = d[i];
                else lpos = d[i] + (V * V - v[i] * v[i]) / (2.0 * a[i]) + eps;
                int ll = lower_bound(p + 1, p + m + 1, lpos) - p;
                range = {ll, m};
            }
            else {
                if (v[i] <= V) range = {0, -1};
                else {
                    double rpos = d[i] + (V * V - v[i] * v[i]) / (2.0 * a[i]) - eps;
                    int rr = lower_bound(p + 1, p + m + 1, rpos) - p - 1;
                    int ll = lower_bound(p + 1, p + m + 1, d[i]) - p;
                    range = {ll, rr};
                }
            }
            // printf("#[%d] %d %d\n", i, range.x, range.y);
            if (range.x > range.y) continue;
            ranges[ ++ cnt] = range;
        }

        printf("%d ", cnt);

        sort(ranges + 1, ranges + cnt + 1);
        memset(st, false, sizeof st);
        priority_queue<PII> heap;

        for (int i = 1; i <= cnt; i ++ ) {
            int r = ranges[i].y;
            while (!heap.empty() && heap.top().x >= r) st[heap.top().y] = true, heap.pop();
            heap.push({r, i});
        }

        idx = 0;
        for (int i = 1; i <= cnt; i ++ )
            if (!st[i])
                new_ranges[ ++ idx] = ranges[i];
        
        int ans = 0;
        for (int i = 1, j = 1; i <= idx; ans ++ , i = j)
            while (j <= idx && new_ranges[j].x <= new_ranges[i].y) j ++ ;
        
        printf("%d\n", m - ans);
    }
}

蒟蒻犯的若至错误

  • 没有处理左右端点的开闭
posted @ 2024-12-21 17:30  是一只小蒟蒻呀  阅读(6)  评论(0编辑  收藏  举报