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.
A merged block’s value is always just the maximum of the original numbers inside it. Nothing fancier is hiding there.
First solve the easier version where the numbers are on a line. Look at the original gaps between consecutive elements.
For a line gap between and , the merge that finally removes that gap must cost at least .
For a line, that lower bound is tight: in any segment, choose a gap adjacent to a maximum element as the last merge, then recurse on both sides.
On the ring, exactly one original cyclic gap can be left unused. Leave the gap with largest weight , so the answer is the sum of all cyclic gap weights minus the largest one.
Let’s name the important thing: gaps, not elements.
For each cyclic gap between neighboring elements, define
where .
The answer is:
That’s the whole trick. Now let’s justify it properly, because otherwise this formula looks like it fell out of the sky wearing sunglasses.
Warm-up: merging a line
Suppose the numbers are not on a ring, but on a line:
Define each line gap weight as
Claim: the minimum cost to merge this line into one element is
Why is this a lower bound?
Consider one original gap between and . At some point, the block containing and the block containing must be merged together for the first time. That merge removes this original gap.
The merged block contains both and , so its value, and therefore the merge cost, is at least
There are exactly original gaps and exactly merges, so every gap contributes at least its weight. Therefore every strategy costs at least
Now the more important part: this lower bound is actually achievable.
Take any segment of the line. Let be the maximum value inside that segment. If the segment has length at least , there is always some internal gap adjacent to an occurrence of , and that gap has weight .
Make that gap the last merge inside this segment. Then recursively merge the left part and the right part first.
By induction:
So the whole segment costs exactly the sum of all its gap weights.
Therefore, for a line, the optimal cost is exactly the sum of adjacent maximums.
Back to the ring
A ring with elements has cyclic gaps:
Each merge removes one current boundary, which corresponds to one original cyclic gap. Since we do exactly merges, exactly of the original gaps get used. One original gap is left unused.
If gap is used, the merge removing it costs at least
So if the unused gap is , the total cost is at least
To minimize this lower bound, we obviously want the unused gap to be the most expensive one. So every strategy costs at least
Can we achieve it? Yep.
Pick a cyclic gap with maximum weight and pretend to cut the ring there. Now the remaining elements form a line, and the line gaps are exactly all cyclic gaps except the one we cut.
From the line result, we can merge this line with cost equal to the sum of those remaining gap weights. Since all those line merges are valid ring merges too, this gives total cost
Lower bound matches construction, so we’re done. No weird priority queue, no fake Huffman cosplay, just gap accounting.
Algorithm
For each test case:
sum.best.sum - best.The values can be up to and there are up to elements, so the answer can be around . Use long long.
Complexity per test case: time and memory, or extra memory if you want to stream carefully. The simple vector version is already totally fine.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n);
for (ll &x : a) cin >> x;
ll sum = 0;
ll best = 0;
for (int i = 0; i < n; i++) {
ll w = max(a[i], a[(i + 1) % n]);
sum += w;
best = max(best, w);
}
cout << sum - best << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<ll> a(n);
for (ll &x : a) cin >> x;
ll sum = 0;
ll best = 0;
for (int i = 0; i < n; i++) {
ll w = max(a[i], a[(i + 1) % n]);
sum += w;
best = max(best, w);
}
cout << sum - best << '\n';
}
}