「WyOJ Round 1」炽 · 踏浪而歌
Solution
算法标签: 贪心。
最小次数分为两种情况:
- 最大值
> 总和- 最大值:最大值。 -
考虑依据答案进行贪心输出字典序最小的方案,令初始的最小次数为
- 将最小位置减
1 。 - 最小位置和次小位置同时减
1 。 - 最小位置和最大值位置同时减
1 。
存在第一种方式是显然的,对于第
于是,只需要维护最大值(使用线段树或 set 维护)并每次一次分讨这三种情况是否可行即可输出字典序最小的方案。
Code
// std
#include <bits/stdc++.h>
using namespace std;
using i64 = long long;
using pii = pair<int, int>;
int ilog(int x) { return 32 - __builtin_clz(x); }
template <class Info>
struct SGT {
std::vector<Info> info;
int N;
SGT() {}
SGT(int _N) { N = 1 << ilog(_N), info.resize(2 * N, Info()); }
SGT(std::vector<Info> _info) {
N = 1 << ilog(_info.size());
info.resize(N * 2, Info());
for (int i = N; i < N + _info.size(); i ++) info[i] = _info[i - N];
for (int i = N - 1; i >= 1; i --) info[i] = info[i * 2] + info[i * 2 + 1];
}
void modify(int x, Info d) {
info[x + N] = d;
for (int i = (x + N) / 2; i >= 1; i /= 2) info[i] = info[i * 2] + info[i * 2 + 1];
}
Info operator[] (pair<int, int> seg) {
int L = seg.first + N, R = seg.second + N;
Info LS = Info(), RS = Info();
for (; L <= R; L = L / 2, R = R / 2) {
if (L & 1) LS = LS + info[L ++];
if (~R & 1) RS = info[R --] + RS;
}
return LS + RS;
}
Info operator[] (int x) { return info[x + N]; }
};
const int inf = 1 << 30;
struct Info {
int mx, pos;
Info(int _ = -inf, int _p = 0): mx(_), pos(_p) {}
};
Info operator+ (Info a, Info b) {
Info c;
if (a.mx >= b.mx) c = a;
else c = b;
return c;
}
const int maxn = 100005;
int n;
int a[maxn];
int main() {
cin.tie(0);
cout.tie(0);
ios::sync_with_stdio(0);
cin >> n;
SGT<Info> sgt(n + 1);
set<int> sp;
int sum = 0;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
if (!a[i]) continue;
sgt.modify(i, {a[i], i});
sp.insert(i), sum += a[i];
}
int res = sgt[{1, n}].mx * 2 > sum ? sgt[{1, n}].mx : sum + 1 >> 1;
std::vector<pii> opt;
while (sp.size() > 1) {
auto check = [&](int u, int v) -> bool {
bool ok = true;
if (u == v) {
a[u] --, sum --;
sgt.modify(u, {a[u], u});
// cout << sgt[{1, n}].mx << " " << sum << endl;
int cur = sgt[{1, n}].mx * 2 > sum ? sgt[{1, n}].mx : sum + 1 >> 1;
if (cur != res - 1) ok = false;
a[u] ++, sum ++, sgt.modify(u, {a[u], u});
} else {
a[u] --, sum --;
a[v] --, sum --;
sgt.modify(u, {a[u], u});
sgt.modify(v, {a[v], v});
int cur = sgt[{1, n}].mx * 2 > sum ? sgt[{1, n}].mx : sum + 1 >> 1;
if (cur != res - 1) ok = false;
a[u] ++, a[v] ++, sum += 2;
sgt.modify(u, {a[u], u});
sgt.modify(v, {a[v], v});
}
return ok;
};
int u = *sp.begin(), v = *next(sp.begin()), w = sgt[{1, n}].pos;
if (check(u, u)) {
sum --, opt.push_back({u, u});
a[u] --, sgt.modify(u, {a[u], u});
if (!a[u]) sp.erase(u);
} else if (check(u, v)) {
opt.push_back({u, v});
a[u] --, a[v] --, sum -= 2;
sgt.modify(u, {a[u], u});
sgt.modify(v, {a[v], v});
if (!a[u]) sp.erase(u);
if (!a[v]) sp.erase(v);
} else {
opt.push_back({u, w});
a[u] --, a[w] --, sum -= 2;
sgt.modify(u, {a[u], u});
sgt.modify(v, {a[v], v});
if (!a[u]) sp.erase(u);
if (!a[w]) sp.erase(w);
}
res --;
}
if (sp.size() == 1) {
int u = *sp.begin();
for (int i = 1; i <= a[u]; i ++)
opt.push_back({u, u});
}
cout << opt.size() << '\n';
for (auto [u, v] : opt)
cout << u << " " << v << '\n';
return 0;
}