2023 February Bronze · All three problems
Problem 1 · Hungry Cow
Statement (paraphrased)
Bessie eats exactly one haybale every day on which she has at least one in storage; otherwise she eats nothing that day. Farmer John makes N deliveries: on day di he drops off bi haybales in the morning before dinner. Output the total number of haybales Bessie consumes during days 1..T.
Constraints
- 1 ≤ N ≤ 105.
- 1 ≤ T ≤ 1014.
- 1 ≤ di ≤ T, strictly increasing.
- 1 ≤ bi ≤ 109. 64-bit ints required.
- Subtasks: inputs 4–7: T ≤ 105; 8–13: full.
- Time / memory: 2 s, 256 MB (default).
Key idea
Walk the deliveries left-to-right tracking cur, the day Bessie will eat next, plus a running stockpile.
Between delivery i and i+1 Bessie eats min(stock, d_{i+1} − cur) haybales — the rest carries forward.
After the last delivery cap the run by T. T is huge but the simulation is O(N) because we collapse each "eating run"
in one arithmetic step instead of iterating day-by-day.
Complexity target
O(N). Day count is virtual — never loop over T.
C++ reference solution
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N; ll T;
cin >> N >> T;
vector<ll> d(N), b(N);
for (int i = 0; i < N; ++i) cin >> d[i] >> b[i];
ll eaten = 0; // total haybales consumed
ll stock = 0; // current stockpile
ll cur = 1; // next day Bessie will try to eat
for (int i = 0; i < N; ++i) {
// eat from cur up to min(d[i]-1, T)
ll until = min(d[i] - 1, T);
if (until >= cur) {
ll take = min(stock, until - cur + 1);
eaten += take;
stock -= take;
cur = until + 1;
}
if (d[i] > T) break;
stock += b[i];
cur = max(cur, d[i]);
}
// tail from cur..T
if (cur <= T) {
ll take = min(stock, T - cur + 1);
eaten += take;
}
cout << eaten << '\n';
return 0;
}
Pitfalls
- Looping over days TLEs and MLEs (T up to 1014). The trick is collapsing each gap to one O(1) step.
- Off-by-one on the inclusive endpoint
T— count days 1..T, not 0..T-1. - Use
long longfor stock, cur, and eaten. Totals reach ~1014.
Problem 2 · Stamp Grid
Statement (paraphrased)
Given a target N×N grid of black/white cells and a K×K stamp also coloured B/W, decide whether you can reproduce the target by repeatedly placing the stamp (in any of its four rotations) onto a blank N×N canvas. Each placement paints all black-cells of the stamp onto the canvas; cells once painted stay painted. White stamp cells leave the canvas unchanged.
Constraints
- 1 ≤ N ≤ 20, 1 ≤ K ≤ N.
- 1 ≤ T ≤ 100 test cases.
- Time / memory: 2 s, 256 MB (default).
Key idea
Try every rotation of the stamp and every top-left placement (N−K+1)2. A placement is "legal" if no black stamp-cell sits on a target-white cell — otherwise it would over-paint a cell that must stay white. Greedily apply every legal placement; you can apply each one at most once because cells only flip W→B. Then check whether the resulting canvas equals the target.
Complexity target
O(4 · N2 · K2) per test case — comfortable with N, K ≤ 20.
C++ reference solution
#include <bits/stdc++.h>
using namespace std;
int N, K;
vector<string> target, canvas;
vector<string> rot(const vector<string>& s){
int n = s.size();
vector<string> r(n, string(n, '.'));
for (int i = 0; i < n; ++i)
for (int j = 0; j < n; ++j)
r[j][n-1-i] = s[i][j];
return r;
}
bool legal(const vector<string>& st, int r, int c){
for (int i = 0; i < K; ++i)
for (int j = 0; j < K; ++j)
if (st[i][j] == '*' && target[r+i][c+j] != '*') return false;
return true;
}
void apply(const vector<string>& st, int r, int c){
for (int i = 0; i < K; ++i)
for (int j = 0; j < K; ++j)
if (st[i][j] == '*') canvas[r+i][c+j] = '*';
}
int main(){
int T; cin >> T;
while (T--){
cin >> N >> K;
target.assign(N, "");
for (auto& s : target) cin >> s;
vector<string> st(K, ""); for (auto& s : st) cin >> s;
canvas.assign(N, string(N, '.'));
for (int rot_i = 0; rot_i < 4; ++rot_i){
for (int r = 0; r + K <= N; ++r)
for (int c = 0; c + K <= N; ++c)
if (legal(st, r, c)) apply(st, r, c);
st = rot(st);
}
cout << (canvas == target ? "YES" : "NO") << '\n';
}
}
Pitfalls
- Rotating a non-square stamp would matter, but K×K means width=height — still, generate all 4 rotations explicitly.
- Don't confuse "legal placement" with "useful placement". Apply every legal one; greedy is exact because painting is monotone.
- Check equality at the end, not just black-cell coverage — you also need every target-white cell to remain white (guaranteed by the legality rule).
Problem 3 · Watching Mooloo
Statement (paraphrased)
Bessie wants to watch on N specific days d1 < … < dN. A subscription covering d consecutive days costs d + K moonies; she may buy as many disjoint blocks as she likes. Minimise total cost so every viewing day is covered.
Constraints
- 1 ≤ N ≤ 105.
- 1 ≤ K ≤ 109.
- 1 ≤ di ≤ 1014, strictly increasing.
- Subtasks: 3–5: N ≤ 10; 6–12: full.
- Time / memory: 2 s, 256 MB. 64-bit ints required.
Key idea
Sort the days (already sorted in input) and consider the gap g = di+1 − di. Extending the current subscription across the gap costs g additional days. Starting a fresh subscription costs 1 + K (1 for the new day, K for the new subscription overhead). So merge while g ≤ K, else split. Final cost = N + K·(blocks) + Σ (kept gaps).
Complexity target
O(N) after the implicit sort. One linear pass.
C++ reference solution
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
int N; ll K;
cin >> N >> K;
vector<ll> d(N);
for (auto& x : d) cin >> x;
ll cost = 1 + K; // first block: 1 day + K
for (int i = 1; i < N; ++i){
ll g = d[i] - d[i-1];
if (g <= K) cost += g; // extend
else cost += 1 + K; // new block
}
cout << cost << '\n';
return 0;
}
Pitfalls
- Off-by-one on the gap formula. Extending di→di+1 adds g days (the new day plus the in-between days), not g−1.
- Use
long longeverywhere — di · K can dwarf 1018 if you mis-formulate. - The greedy is exact because subscription overhead K is fixed; there's no DP to do.