[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);
}
}
蒟蒻犯的若至错误
- 没有处理左右端点的开闭