题解:AtCoder AT_awc0125_b Defense of the Flower Bed
【题目来源】
AtCoder:B - Defense of the Flower Bed
【题目描述】
高橋正在种植一排 \(N\) 盆盆栽植物。它们从左到右编号为 \(1, 2, \ldots, N\),植物 \(i\) 目前含有 \(A_i\) 毫升水。
由于夏季炎热,每天所有盆栽植物的水都会蒸发。具体来说,每过一天,每盆植物中的水量减少 \(D\) 毫升(但水量不会降到 \(0\) 以下,最低为 \(0\))。
与此同时,淘气的青木正计划破坏高橋的花坛。青木可以在每天开始时最多执行一次操作:他可以选择任意一盆植物,将其水量设为 \(0\)(一种倒掉水的恶作剧)。青木总共最多可以执行 \(K\) 次这样的操作。他可以选择同一盆植物多次。青木的恶作剧在该天的蒸发发生之前执行。
高橋无法补充水,也无法阻止蒸发或青木的恶作剧。他希望 \(M\) 天后(所有 \(M\) 天的蒸发和青木的恶作剧都完成后),剩余水量至少为 \(1\) 毫升的盆栽植物数量尽可能多。
青木会采取最优策略,使高橋面临最糟糕的结果。换句话说,青木选择恶作剧的目标,以最小化 \(M\) 天后剩余水量至少为 \(1\) 毫升的盆栽植物数量。
假设青木采取最优策略,求 \(M\) 天后剩余水量至少为 \(1\) 毫升的盆栽植物数量。
【输入】
\(N\) \(M\) \(D\) \(K\)
\(A_1\) \(A_2\) \(\ldots\) \(A_N\)
- The first line contains the number of potted plants \(N\), the number of days \(M\), the daily evaporation amount \(D\), and the maximum number of Aoki's pranks \(K\), separated by spaces.
- The second line contains the initial water amounts of the potted plants \(A_1, A_2, \ldots, A_N\), separated by spaces.
【输出】
Print the number of potted plants with at least \(1\) milliliter of water remaining after \(M\) days, assuming Aoki acts optimally, in a single line.
【输入样例】
5 3 2 1
1 5 6 7 10
【输出样例】
1
【核心思想】
-
问题分析:给定 \(N\) 盆植物初始水量 \(A_i\),每天蒸发 \(D\) 毫升(不低于 0),青木在每天蒸发前最多恶作剧一次(将某盆水置 0),总共最多 \(K\) 次。\(M\) 天后求剩余水量 \(\geq 1\) 的植物最大数量(青木采取最优策略最小化该数量)。
-
算法选择:
- 分类讨论 + 贪心:将植物分为两类——仅靠蒸发就会干枯的(\(A_i \leq M \cdot D\))和蒸发后仍有剩余的(\(A_i > M \cdot D\))
- 青木最优策略:优先消灭"蒸发后仍有剩余"的植物(这些植物不消灭就会存活),每次恶作剧消灭一盆
-
关键步骤:
- 读入与排序:读入 \(N, M, D, K\) 和数组 \(A[1..N]\),将 \(A\) 从小到大排序
- 统计蒸发干枯数:遍历排序后的数组,统计满足 \(A_i \leq M \cdot D\) 的数量 \(ans\)(这些植物无需青木干预)
- 修正恶作剧次数:\(K = \min(K, M)\),青木每天最多一次,总次数不超过天数 \(M\)
- 计算存活数:蒸发后仍有剩余的植物数为 \(N - ans\),青木最多消灭 \(\min(K, N - ans)\) 盆,最终存活数为 \(\max(0, N - ans - K)\)
-
时间/空间复杂度:
- 时间复杂度:\(O(N \log N)\),排序主导;统计过程 \(O(N)\)
- 空间复杂度:\(O(N)\),存储水量数组
-
贪心策略的核心思想:
- 自然淘汰与人为干预分离:\(A_i \leq M \cdot D\) 的植物必然干枯,青木无需浪费恶作剧次数
- 优先打击"幸存者":青木的最优策略是集中力量消灭那些仅靠蒸发无法消灭的植物,每消灭一盆直接减少一个存活者
- 次数上限约束:恶作剧次数受 \(K\) 和 \(M\) 双重限制,取 \(\min(K, M)\) 为实际可用次数
- 排序便于分界:排序后 \(A_i \leq M \cdot D\) 的植物集中在数组前端,一次遍历即可统计
- 适用于"资源有限的最优打击"类问题,核心在于识别无需干预的"自然死亡"目标
【算法标签】
贪心
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 将int定义为long long,避免水量计算溢出
const int N = 1000005; // 定义数组最大容量为1000005
int n, m, d, k, ans; // n为盆栽数量,m为天数,d为每天蒸发量,k为青木最多恶作剧次数,ans记录特定统计值
int a[N]; // a[i]表示第i盆植物的初始水量
signed main() // 使用signed main配合#define int long long
{
cin >> n >> m >> d >> k; // 读入盆栽数n、天数m、蒸发量d、恶作剧次数k
for (int i = 1; i <= n; i++) // 读入每盆植物的初始水量
cin >> a[i];
sort(a + 1, a + n + 1); // 将初始水量从小到大排序
// 统计:经过M天蒸发后(不考虑青木恶作剧),水量会降到0的植物数量
// 每天蒸发D,M天共蒸发M*D,如果a[i] <= M*D,则蒸发后水量为0(或更低)
for (int i = 1; i <= n; i++)
{
if (a[i] <= m * d) // 如果初始水量不超过M天总蒸发量
ans++; // 该植物仅靠蒸发就会干枯(水量变为0)
}
// 青木每天最多恶作剧一次,总共最多K次
// 但恶作剧天数不能超过总天数M,所以实际最多min(K, M)次
k = min(k, m); // 修正k为实际可用的恶作剧次数
// 核心逻辑:
// ans:仅靠蒸发就会干枯的植物数量(这些植物不需要青木操心)
// n - ans:仅靠蒸发不会干枯的植物数量(a[i] > M*D,这些植物需要青木恶作剧才能消灭)
// 青木最多可以消灭k盆植物(每次恶作剧将一盆植物水量设为0)
// 最终存活数 = 总植物数 - 蒸发干枯数 - 青木消灭数
// = n - ans - min(k, n - ans)
// = max(0, n - ans - k)
cout << max(0LL, n - ans - k) << endl; // 输出M天后剩余水量至少为1毫升的盆栽数量
return 0;
}
【运行结果】
5 3 2 1
1 5 6 7 10
1
浙公网安备 33010602011771号