题解:洛谷 P2909 Cow Cars

【题目来源】

洛谷:P2909 [USACO08OPEN] Cow Cars S - 洛谷

【题目描述】

在 Cowtopia 的高速公路上,有 \(N\) 头奶牛(\(1 \leq N \leq 50,000\)),它们被方便地编号为 \(1..N\),分别驾驶着不同的汽车。奶牛 \(i\) 可以在 \(M\) 条不同的高速车道上行驶(\(1 \leq M \leq N\)),并且可以以最大速度 \(S_i\)\(1 \leq S_i \leq 1,000,000\))公里/小时行驶。

在经历了其他糟糕的驾驶体验后,奶牛们讨厌碰撞,并采取了极端措施来避免它们。在这条高速公路上,奶牛 \(i\) 会因为在它前面的每一头奶牛而将速度减少 \(D\)\(0 \leq D \leq 5,000\))公里/小时(但速度不会低于 0 公里/小时)。因此,如果在奶牛 \(i\) 前面有 \(K\) 头奶牛,那么它将以 \(\max[S_i - D \times K, 0]\) 的速度行驶。虽然奶牛实际上可能比直接在它前面的奶牛行驶得更快,但奶牛之间的间距足够大,因此一旦奶牛减速,就不会发生碰撞。

Cowtopia 有一条最低速度法则,要求高速公路上的所有车辆都必须以最低速度 \(L\)\(1 \leq L \leq 1,000,000\))公里/小时行驶,因此有时一些奶牛在遵循上述规则时将无法上高速公路。编写一个程序,找出在遵守最低速度限制法的情况下,能够在高速公路上行驶的最大奶牛数量。

【输入】

* 第 1 行:四个以空格分隔的整数:\(N\)\(M\)\(D\)\(L\)

* 第 2 行到第 \(N+1\) 行:第 \(i+1\) 行用一个整数描述奶牛 \(i\) 的初始速度:\(S_i\)

【输出】

* 第 1 行:一个整数,表示可以使用高速公路的最大奶牛数量

【输入样例】

3 1 1 5
5
7
5

【输出样例】

2

【核心思想】

  1. 问题分析:给定 \(N\) 头奶牛的初始速度 \(S_i\)\(M\) 条车道,减速规则为前面有 \(K\) 头牛时速度变为 \(\max(S_i - D \times K, 0)\),最低限速为 \(L\)。求能上高速的最大奶牛数量。这是一个贪心排序 + 模拟分配问题,关键在于将速度慢的奶牛优先安排(减少后续减速影响),并用 \(K = \lfloor \text{已安排数} / M \rfloor\) 计算当前牛前面的牛数量。

  2. 算法选择

    • 贪心排序:按速度从小到大排序,优先安排速度慢的奶牛。因为速度慢的奶牛对减速更敏感,先安排可确保它们在 \(K\) 较小时就满足条件
    • 车道轮询模拟\(K = ans / M\) 表示当前要安排的牛前面已有的牛数(已安排的 \(ans\) 头牛平均分配到 \(M\) 条车道,每条车道有 \(K\)\(K+1\) 头)
  3. 关键步骤

    • 读取输入\(N, M, D, L\)\(N\) 个速度 \(S_i\)
    • 排序sort(a+1, a+N+1),速度升序
    • 贪心安排\(i\)\(1\)\(N\)):
      • \(K = ans / M\):当前牛若加入,前面平均有 \(K\) 头牛
      • \(S_i - K \times D \ge L\):满足限速,\(ans \mathrel{+}= 1\)
    • 输出 \(ans\)
  4. 时间/空间复杂度

    • 时间复杂度:\(O(N \log N)\),排序主导
    • 空间复杂度:\(O(N)\),存储速度数组
  5. 贪心排序的核心思想

    • 慢牛优先:速度慢的奶牛对减速更敏感(\(S_i - K \times D\) 更容易低于 \(L\)),优先安排可确保它们在 \(K\) 较小时就被选中
    • 车道均衡\(ans / M\) 假设牛被均衡分配到 \(M\) 条车道,当前新牛加入任一车道的最坏情况就是前面有 \(\lceil ans / M \rceil\) 头牛。由于我们按最坏情况估计(\(K = \lfloor ans / M \rfloor\)),若此时满足条件则实际安排一定可行
    • 最优性保证:将速度慢的牛放在前面,快的牛放在后面承受更多减速但仍可能满足条件,这是最大化数量的最优策略
    • 适用于"排序后贪心验证 + 资源均衡分配"类问题,核心是理解 \(K\) 的计算方式和排序策略

【解题思路】

【算法标签】

普及- #贪心

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, m, d, l, a[50005], ans=0;
int main()
{
    cin >> n >> m >> d >> l;  // 输入n、m、d和l
    for (int i=1; i<=n; i++) {  // 输入n个奶牛的速度
        cin >> a[i];
    }
    sort(a+1, a+n+1);  // 按照从小到大排序(不能将小的放后面,因为s-k*d后越来越小)
    for (int i=1; i<=n; i++) {  // 遍历n头奶牛
        int k = ans/m;  // 计算k值,将多个ans放到不同m中,如ans 1和2对应k 1,ans 3和4对应k 2
        if (a[i]-k*d>=l) ans++;  // 按照题意,车速不能低于l
    }
    cout << ans << endl;  // 输出结果
    return 0;
}

【运行结果】

3 1 1 5
5
7
5
2
posted @ 2026-08-28 15:55  团爸讲算法  阅读(4)  评论(0)    收藏  举报