题解:洛谷 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
【核心思想】
-
问题分析:给定 \(N\) 头奶牛的初始速度 \(S_i\),\(M\) 条车道,减速规则为前面有 \(K\) 头牛时速度变为 \(\max(S_i - D \times K, 0)\),最低限速为 \(L\)。求能上高速的最大奶牛数量。这是一个贪心排序 + 模拟分配问题,关键在于将速度慢的奶牛优先安排(减少后续减速影响),并用 \(K = \lfloor \text{已安排数} / M \rfloor\) 计算当前牛前面的牛数量。
-
算法选择:
- 贪心排序:按速度从小到大排序,优先安排速度慢的奶牛。因为速度慢的奶牛对减速更敏感,先安排可确保它们在 \(K\) 较小时就满足条件
- 车道轮询模拟:\(K = ans / M\) 表示当前要安排的牛前面已有的牛数(已安排的 \(ans\) 头牛平均分配到 \(M\) 条车道,每条车道有 \(K\) 或 \(K+1\) 头)
-
关键步骤:
- 读取输入:\(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\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\),排序主导
- 空间复杂度:\(O(N)\),存储速度数组
-
贪心排序的核心思想:
- 慢牛优先:速度慢的奶牛对减速更敏感(\(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
浙公网安备 33010602011771号