求调
查看原帖
求调
750444
chen__yu楼主2025/8/5 11:58

50pts, 加速和平速有点问题,注释是豆包写的

#include<bits/stdc++.h>
#define int long long  // 定义int为long long,避免整数溢出
using namespace std;

const int N = 1e5 + 5;  // 数组最大长度,适应题目中1e5的数量级
int T;  // 测试数据组数

// 存储车辆信息的结构体
struct node {
    int d, v, a;  // d:驶入位置,v:初速度,a:加速度
    double l, r;  // 超速区间的左右端点(位置)
    bool vis;     // 标记车辆是否超速及类型(0:不超速,1/2/3:不同类型的超速)
} c[N];

// 存储超速车辆对应测速仪索引区间的结构体
struct node2 {
    int l, r;  // 测速仪索引的区间[左,右]
    // 排序运算符重载:按右端点升序,右端点相同时按左端点升序
    bool friend operator < (node2 a, node2 b) {
        if(a.r != b.r)
            return a.r < b.r;
        return a.l < b.l;
    }
} k[N];

int p[N];  // 存储测速仪位置(已排序)

void solve() {
    int tot = 0;  // 记录超速车辆的数量(用于第二问)
    // 初始化数组(实际可省略,因每次都会重新赋值)
    memset(c, 0, sizeof(c));
    memset(k, 0, sizeof(k));
    memset(p, 0, sizeof(p));
    
    int n, m, L, V;  // n:车辆数,m:测速仪数,L:主干道长度,V:限速
    cin >> n >> m >> L >> V;
    
    // 读入n辆车的信息
    for(int i = 1; i <= n; i++)
        cin >> c[i].d >> c[i].v >> c[i].a;
    
    // 读入m个测速仪的位置(题目保证已按升序排列)
    for(int i = 1; i <= m; i++)
        cin >> p[i];
    
    int ans = 0;  // 第一问答案:所有测速仪开启时超速的车辆数
    int sum = 0;  // 第二问辅助变量:最少需要保留的测速仪数量
    
    // 处理每辆车,判断是否超速
    for(int i = 1; i <= n; i++) {
        int d = c[i].d, v = c[i].v, a = c[i].a;
        
        // 情况1:加速度a < 0(减速运动)
        if(a < 0) {
            // 初速度 <= 限速,不会超速
            if(v <= V)
                continue;
            
            // 计算超速区间左端点:驶入位置d
            c[i].l = d;
            // 计算速度减到V时的位置:s = (V² - v²)/(2a) + d(因a为负,是减速到V的位移)
            c[i].r = double((V * V - v * v * 1.0) / (2.0 * a)) + d;
            
            // 查找第一个 >= 左端点的测速仪位置
            int id = lower_bound(p + 1, p + 1 + m, c[i].l) - p;
            if(id == m + 1)  // 没有符合条件的测速仪,不超速
                continue;
            
            // 若超速区间右端点超过主干道终点L,修正为L
            if(c[i].r > L) {
                c[i].r = L;
                ans++;  // 该车辆超速
                c[i].vis = 2;  // 标记类型2:区间到L结束
            }
            // 否则,若存在测速仪在区间内,该车辆超速
            else if(p[id] < c[i].r) {
                ans++;
                c[i].vis = 1;  // 标记类型1:区间在L内结束
            }
        }
        
        // 情况2:加速度a = 0(匀速运动)
        if(a == 0) {
            // 速度 <= 限速,不会超速
            if(v <= V)
                continue;
            
            // 超速区间:从驶入位置d到主干道终点L
            c[i].l = d;
            c[i].r = L;
            
            // 查找第一个 >= 左端点的测速仪位置
            int id = lower_bound(p + 1, p + 1 + m, c[i].l) - p;
            if(id != m + 1) {  // 存在符合条件的测速仪,该车辆超速
                ans++;
                c[i].vis = 2;  // 标记类型2
            }
        }
        
        // 情况3:加速度a > 0(加速运动)
        if(a > 0) {
            // 初速度 > 限速,全程超速(从d到L)
            if(v > V) {
                c[i].l = d;
                c[i].r = L;
                // 查找第一个 >= 左端点的测速仪位置
                int id = lower_bound(p + 1, p + 1 + m, c[i].l) - p;
                if(id != m + 1) {  // 存在符合条件的测速仪,该车辆超速
                    ans++;
                    c[i].vis = 2;  // 标记类型2
                }
                continue;
            }
            
            // 初速度 <= 限速,计算加速到V时的位移s
            double s = max((double)((V * V - v * v * 1.0) / (2.0 * a)), 0.0);
            // 若加速到V时已超过主干道终点,不会超速
            if(d + s >= L)
                continue;
            
            // 超速区间:从加速到V的位置(d+s)到L
            c[i].l = d + s;
            c[i].r = L;
            
            // 查找第一个 > 左端点的测速仪位置(因左端点处速度等于V,不超速)
            int id = upper_bound(p + 1, p + 1 + m, c[i].l) - p;
            if(id != m + 1) {  // 存在符合条件的测速仪,该车辆超速
                ans++;
                c[i].vis = 3;  // 标记类型3:左端点是加速到V的位置
            }
        }
    }
    
    // 处理第二问:收集所有超速车辆对应的测速仪索引区间
    for(int i = 1; i <= n; i++) {
        if(c[i].vis != 0) {  // 只处理超速车辆
            int id, id2;  // 测速仪索引区间[ id, id2 ]
            
            // 根据车辆超速类型计算区间
            if(c[i].vis == 1) {
                // 类型1:超速区间[l, r),找>=l且<r的测速仪
                id = lower_bound(p + 1, p + 1 + m, c[i].l) - p;
                id2 = lower_bound(p + 1, p + 1 + m, c[i].r) - p - 1;
            }
            if(c[i].vis == 2) {
                // 类型2:超速区间[l, r],找>=l且<=r的测速仪
                id = lower_bound(p + 1, p + 1 + m, c[i].l) - p;
                id2 = upper_bound(p + 1, p + 1 + m, c[i].r) - p - 1;
            }
            if(c[i].vis == 3) {
                // 类型3:超速区间(l, r],找>l且<=r的测速仪
                id = upper_bound(p + 1, p + 1 + m, c[i].l) - p;
                id2 = upper_bound(p + 1, p + 1 + m, c[i].r) - p - 1;
            }
            
            // 存储该区间(仅当有效时)
            if(id <= id2) {
                k[++tot] = {id, id2};
            }
        }
    }
    
    // 若没有超速车辆,所有测速仪都可关闭
    if(tot == 0) {
        cout << ans << ' ' << m << '\n';
        return ;
    }
    
    // 贪心算法:求覆盖所有区间的最少点数(测速仪)
    sort(k + 1, k + 1 + tot);  // 按区间右端点升序排序
    int nr = 0;  // 记录当前选择的测速仪索引
    for(int i = 1; i <= tot; i++) {
        // 若当前区间左端点 > 已选的最右索引,需新选一个测速仪(选当前区间右端点)
        if(k[i].l > nr) {
            sum++;  // 增加保留的测速仪数量
            nr = k[i].r;  // 更新最右索引
        }
    }
    
    // 输出结果:第一问答案,第二问答案(总测速仪数 - 最少保留数)
    cout << ans << ' ' << m - sum << '\n';
}

signed main() {
    // 重定向输入输出(调试时使用)
    // freopen("detect3.in", "r", stdin);
    // freopen("detect.out", "w", stdout);
    
    cin >> T;  // 读入测试组数
    while(T--) {
        solve();  // 处理每组测试数据
    }
}
2025/8/5 11:58
加载中...