按送草日期扫描,用剩余草包数和区间长度一次性结算连续多天的吃草数量。
OJ: usaco
题目 ID: 1299
难度:普及-
标签:模拟按时间扫描
日期: 2026-07-11 13:03
题意
FJ 会在若干天的早上送来草包。每天晚上,如果仓库里还有草包,Bessie 就吃掉一个。
给定前 T 天内每次送草的日期和数量,求 Bessie 在第 1 天到第 T 天一共吃掉多少个草包。
思路
暴力想法
最直接的做法是逐日模拟:每天早上加入当天送来的草包,晚上如果仓库不空就吃一个。
这个做法完全贴合题意,适合小数据理解:
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 13:03
* update_at: 2026-07-11 13:08
*/
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 105;
int n;
long long T;
long long day_arr[MAXN];
long long bale_arr[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> T;
for (int i = 1; i <= n; i++) {
cin >> day_arr[i] >> bale_arr[i];
}
long long remain = 0;
long long answer = 0;
int pos = 1;
// 暴力直接逐日模拟,只适合 T 很小的数据。
for (long long day = 1; day <= T; day++) {
if (pos <= n && day_arr[pos] == day) {
remain += bale_arr[pos];
pos++;
}
if (remain > 0) {
remain--;
answer++;
}
}
cout << answer << '\n';
return 0;
}但是
按送草日期扫描
观察相邻两次送草之间没有新的事件发生。假设当前剩余 remain 个草包,距离下一次送草还有 days 天,那么这段时间能吃掉:
如果草包不够,就把已有草包吃完;如果草包足够,就每天吃一个,吃满 days 天。
因此不需要逐日模拟,只要按送草日期扫描:
text
eat = min(remain, days)
answer += eat
remain -= eat
remain += 本次送来的草包为了统一处理最后一次送草到第 T 天之间的区间,可以在第 T+1 天加一个数量为 0 的哨兵送草。这样最后一段也会被同一套逻辑结算。
代码
cpp
/**
* Author by Rainboy blog: https://rainboylv.com github: https://github.com/rainboylvx
* rbook: -> https://rbook.roj.ac.cn https://rbook2.roj.ac.cn
* rainboy的学习导航网站: https://idx.roj.ac.cn
* create_at: 2026-07-11 13:03
* update_at: 2026-07-11 13:08
*/
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
int n;
long long T;
long long day_arr[MAXN];
long long bale_arr[MAXN];
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> T;
for (int i = 1; i <= n; i++) {
cin >> day_arr[i] >> bale_arr[i];
}
// 哨兵交货日,用来统一处理最后一次交货到第 T 天的吃草过程。
day_arr[n + 1] = T + 1;
bale_arr[n + 1] = 0;
long long remain = 0; // 当前仓库里还剩多少草包。
long long answer = 0; // 前 T 天实际吃掉的草包数。
long long last_day = 1; // 上一次开始统计吃草的日期。
for (int i = 1; i <= n + 1; i++) {
long long days = day_arr[i] - last_day;
long long eat = min(remain, days);
answer += eat;
remain -= eat;
remain += bale_arr[i];
last_day = day_arr[i];
}
cout << answer << '\n';
return 0;
}复杂度
每次送草只处理一次,时间复杂度为
保存送草日期和数量,空间复杂度为
所有日期、草包数量和答案都可能达到 long long。
总结
这题的关键是把“每天吃一个”的过程压缩成区间结算。
相邻两次送草之间,唯一需要知道的是当前剩余草包数和区间长度,所以每段用一次 min(remain, days) 就能统计吃掉多少。