Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Don’t try to brute-force sums. If is the smallest value where greedy fails, then every value is greedy-optimal. That minimality is the only thing keeping this problem from being evil.
Compare the greedy representation of the smallest bad with some optimal representation of . They must coincide on a prefix of the largest denominations. Strip that common prefix away and stare at the first denomination where they differ.
Suppose the first disagreement happens at denomination . After removing the common prefix, the remaining value is . So the special number to look at is not random at all: it is , the largest value still below that bigger coin.
There is a classical characterization (Pearson): if a counterexample exists, then the smallest one can be built from the greedy representation of . Take , choose some , add one coin of value , and erase all smaller denominations. That gives only candidates.
For every , compute . For every , build
g_k,&k<j,\\ g_j+1,&k=j,\\ 0,&k>j. \end{cases}$$ Let $$w=\sum_{k=1}^n m_k a_k,\qquad c=\sum_{k=1}^n m_k.$$ Now just recompute greedy on $w$. If greedy uses more than $c$ coins, then $w$ is a counterexample. Take the minimum over all such $w$; if none exist, answer $-1$.Call the system canonical if greedy is always optimal. We need the smallest value for which greedy is not optimal.
This is one of those problems where brute force is not just slow — it’s mathematically the wrong attack. Coin values go up to , so if you don’t exploit structure, you’re toast.
The coin values are already given in decreasing order:
Let:
We want the smallest such that there exists some representation with
The hard part is a classical characterization due to Pearson.
If greedy ever fails, then the smallest counterexample has a very special form. There exist indices such that, if then an optimal representation of the smallest counterexample is
g_k,&k<j,\\ g_j+1,&k=j,\\ 0,&k>j. \end{cases}$$
In words: take greedy on , add one extra coin of denomination , and kill the whole smaller tail.
That’s the whole damn trick. Without this theorem, the search space is enormous. With it, only candidates survive.
A full proof is a bit technical, but the intuition is clean:
So the smallest bad value can’t be some random Frankenstein number. It has this rigid shape.
For every :
If no candidate works, the system is canonical and the answer is .
For fixed , once we know , we don’t need to rebuild each candidate from scratch.
If we sweep from left to right, maintain: Then the candidate for this is simply:
That makes candidate generation each after the greedy vector is known.
For coins :
So is a counterexample, and in fact the smallest one.
We check every candidate guaranteed by Pearson’s theorem. Therefore, if a counterexample exists, the smallest one will appear in our enumeration.
For each enumerated candidate , we explicitly have a representation using coins. If then greedy is not optimal for , so is indeed a valid counterexample.
Thus:
There are candidates. For each one, we may recompute greedy in time. So total complexity is which is perfectly fine for .
Memory usage is
Short version: the theorem does the heavy lifting, the code just cashes the check.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
static vector<ll> greedyRep(ll x, const vector<ll>& a) {
int n = (int)a.size();
vector<ll> g(n);
for (int i = 0; i < n; ++i) {
g[i] = x / a[i];
x %= a[i];
}
return g;
}
static ll greedyCount(ll x, const vector<ll>& a) {
ll cnt = 0;
for (ll coin : a) {
cnt += x / coin;
x %= coin;
}
return cnt;
}
int main() { setIO();
int n;
cin >> n;
vector<ll> a(n);
for (ll &x : a) cin >> x;
const ll INF = (1LL << 62);
ll ans = INF;
// Pearson's characterization:
// for each i, look at greedy(a[i-1] - 1), then for each j >= i
// form the candidate by adding one a[j] and zeroing smaller coins.
for (int i = 1; i < n; ++i) {
vector<ll> g = greedyRep(a[i - 1] - 1, a);
ll prefValue = 0;
ll prefCoins = 0;
for (int j = 0; j < n; ++j) {
prefValue += g[j] * a[j];
prefCoins += g[j];
if (j < i) continue;
ll w = prefValue + a[j]; // candidate value
ll c = prefCoins + 1; // candidate number of coins
if (greedyCount(w, a) > c) {
ans = min(ans, w);
}
}
}
if (ans == INF) cout << -1 << '\n';
else cout << ans << '\n';
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
static vector<ll> greedyRep(ll x, const vector<ll>& a) {
int n = (int)a.size();
vector<ll> g(n);
for (int i = 0; i < n; ++i) {
g[i] = x / a[i];
x %= a[i];
}
return g;
}
static ll greedyCount(ll x, const vector<ll>& a) {
ll cnt = 0;
for (ll coin : a) {
cnt += x / coin;
x %= coin;
}
return cnt;
}
int main() { setIO();
int n;
cin >> n;
vector<ll> a(n);
for (ll &x : a) cin >> x;
const ll INF = (1LL << 62);
ll ans = INF;
// Pearson's characterization:
// for each i, look at greedy(a[i-1] - 1), then for each j >= i
// form the candidate by adding one a[j] and zeroing smaller coins.
for (int i = 1; i < n; ++i) {
vector<ll> g = greedyRep(a[i - 1] - 1, a);
ll prefValue = 0;
ll prefCoins = 0;
for (int j = 0; j < n; ++j) {
prefValue += g[j] * a[j];
prefCoins += g[j];
if (j < i) continue;
ll w = prefValue + a[j]; // candidate value
ll c = prefCoins + 1; // candidate number of coins
if (greedyCount(w, a) > c) {
ans = min(ans, w);
}
}
}
if (ans == INF) cout << -1 << '\n';
else cout << ans << '\n';
}