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.
First, stop staring at the whole array. Look at one value . What values can become when is arbitrary? Try a few examples like and see the pattern.
For a target value , an element can produce it iff either (choose ), or (choose ). So each element is either an exact match for itself, or a donor for any small enough value.
Suppose you want to make . If some value already exists in the array, you can assume one copy of is used to produce exactly . That’s an exchange argument: if a huge element was covering and the actual was used for something smaller, just swap them. The huge guy can still cover the smaller thing.
After reserving one copy of every present value in , the only remaining job is to fill the missing values in . Every leftover element can cover any missing value in . For interval-type matching like this, check every suffix : the number of missing targets there must be at most the number of leftover elements with capacity at least .
If you simplify that suffix condition, you get the killer formula
Now think online. When you append a value :
Take one value and choose any . What values can be?
A value is achievable iff:
If , then
So necessarily , i.e.
And that condition is also sufficient: choose
then and .
So an element can produce exactly the values
Equivalently, for a target :
That’s the whole damn problem in one line.
Suppose we want to make all values appear.
Claim: in some optimal construction, for every value that is present in the array, one copy of is used to produce exactly .
Why? Suppose not. Then target is covered by some other element , so we must have . Meanwhile the actual value is either unused or used to produce some smaller value .
Now swap:
This is valid because
so can also produce .
So reserving one copy of each present for itself is never worse. No black magic, just a clean exchange argument.
After reserving one copy of every present value in , the only targets still missing are those with .
What about the remaining elements? Each leftover element can produce any value up to
So it acts like a donor for any target in the interval .
Now we just need to match each missing target to a distinct donor whose capacity is large enough. That’s a standard interval matching situation.
For such intervals , feasibility is equivalent to checking every suffix: for every ,
the number of missing targets in must be at most the number of donors with capacity at least .
Let’s write that down.
Fix .
There are values there total, and exactly
of them are already present. So the number of missing ones is
An element has capacity at least iff
Among those elements, if and value exists, one copy of was reserved for itself, so only the rest are available as donors. Thus the number of available donors is
Feasibility gives
Rearrange:
This must hold for every . So the maximum possible is
That’s the formula. The monster is slain.
For each prefix, define
where
Then the answer for the current prefix is just
Now append a new value .
The new element contributes to iff
So we add to all in the range
This depends only on whether is present at least once. So only the first occurrence of matters. If it is the first occurrence, then belongs to interval exactly when
So we add to all in
That’s two range-add updates per element, and after each prefix we need the global minimum. Classic segment tree with lazy propagation:
We proved:
Done. No DP acrobatics, no cursed flow, just a clean invariant and a segment tree beating the hell out of range updates.
Let in one test case.
So each test runs in
and over all tests the total is safe because
Memory is .
Very comfortable under the limits.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<int> mn, lz;
SegTree() : n(0) {}
SegTree(int _n) { init(_n); }
void init(int _n) {
n = _n;
mn.assign(4 * n + 5, 0);
lz.assign(4 * n + 5, 0);
build(1, 0, n - 1);
}
void build(int p, int l, int r) {
if (l == r) {
mn[p] = l; // initial val[t] = t
return;
}
int m = (l + r) >> 1;
build(p << 1, l, m);
build(p << 1 | 1, m + 1, r);
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
}
void apply(int p, int v) {
mn[p] += v;
lz[p] += v;
}
void push(int p) {
if (lz[p] != 0) {
apply(p << 1, lz[p]);
apply(p << 1 | 1, lz[p]);
lz[p] = 0;
}
}
void add(int p, int l, int r, int ql, int qr, int v) {
if (ql > r || qr < l) return;
if (ql <= l && r <= qr) {
apply(p, v);
return;
}
push(p);
int m = (l + r) >> 1;
add(p << 1, l, m, ql, qr, v);
add(p << 1 | 1, m + 1, r, ql, qr, v);
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
}
void add(int l, int r, int v) {
if (l > r) return;
add(1, 0, n - 1, l, r, v);
}
int getMin() const {
return mn[1];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
int mx = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
mx = max(mx, a[i]);
}
// We maintain val[t] for t in [0, mx].
// For t > mx, val[t] = t, which is never better than val[mx] or current answer.
SegTree st(mx + 1);
vector<int> cnt(mx + 1, 0);
for (int i = 0; i < n; ++i) {
int x = a[i];
// Contribution to count of elements >= 2t+1
int r1 = (x - 1) / 2;
if (x >= 1) st.add(0, r1, 1);
// First occurrence contributes to distinct values in [t, 2t]
if (cnt[x] == 0) {
int l2 = (x + 1) / 2;
int r2 = x;
st.add(l2, r2, 1);
}
cnt[x]++;
cout << st.getMin() << (i + 1 == n ? '\n' : ' ');
}
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct SegTree {
int n;
vector<int> mn, lz;
SegTree() : n(0) {}
SegTree(int _n) { init(_n); }
void init(int _n) {
n = _n;
mn.assign(4 * n + 5, 0);
lz.assign(4 * n + 5, 0);
build(1, 0, n - 1);
}
void build(int p, int l, int r) {
if (l == r) {
mn[p] = l; // initial val[t] = t
return;
}
int m = (l + r) >> 1;
build(p << 1, l, m);
build(p << 1 | 1, m + 1, r);
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
}
void apply(int p, int v) {
mn[p] += v;
lz[p] += v;
}
void push(int p) {
if (lz[p] != 0) {
apply(p << 1, lz[p]);
apply(p << 1 | 1, lz[p]);
lz[p] = 0;
}
}
void add(int p, int l, int r, int ql, int qr, int v) {
if (ql > r || qr < l) return;
if (ql <= l && r <= qr) {
apply(p, v);
return;
}
push(p);
int m = (l + r) >> 1;
add(p << 1, l, m, ql, qr, v);
add(p << 1 | 1, m + 1, r, ql, qr, v);
mn[p] = min(mn[p << 1], mn[p << 1 | 1]);
}
void add(int l, int r, int v) {
if (l > r) return;
add(1, 0, n - 1, l, r, v);
}
int getMin() const {
return mn[1];
}
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
vector<int> a(n);
int mx = 0;
for (int i = 0; i < n; ++i) {
cin >> a[i];
mx = max(mx, a[i]);
}
// We maintain val[t] for t in [0, mx].
// For t > mx, val[t] = t, which is never better than val[mx] or current answer.
SegTree st(mx + 1);
vector<int> cnt(mx + 1, 0);
for (int i = 0; i < n; ++i) {
int x = a[i];
// Contribution to count of elements >= 2t+1
int r1 = (x - 1) / 2;
if (x >= 1) st.add(0, r1, 1);
// First occurrence contributes to distinct values in [t, 2t]
if (cnt[x] == 0) {
int l2 = (x + 1) / 2;
int r2 = x;
st.add(l2, r2, 1);
}
cnt[x]++;
cout << st.getMin() << (i + 1 == n ? '\n' : ' ');
}
}
return 0;
}