2020-2021 Winter Petrozavodsk Camp, Day 9 Contest-线段树
Description
给出一个\(a\),选出\(7\)个数要求\(P_1\ge P_2\ge P_3\ge P_4\ge P_5 \ge P_6 \ge P_7\)
并且使得\(P_1<P_2+P_3<P_4+P_5+P_6+P_7\),最后令\(7\)个数的和最大
Solution
先对\(a\)数组降序排序
考虑\(P_3\),容易发现如果\(P_3\)的位置确定,那么\(P_3\)到\(P_7\)放在连续的一段一定是最优的
那么可以枚举\(P_3\)的位置,根据\(P_2<P_4+P_5+P_6+P_7-P_3\)找到\(P_2\)最左侧的可行位置\(pos\),并对\([pos,P_3-1]\)这段区间进行赋值为\(P_3\)的位置
这样就能得出在\(P_2\)位置确定的情况下,\(P_3\)的最优位置,同理根据\(P_1<P_3-P_2\)找出最优的\(P_1\)更新答案
用线段树即可进行区间赋值和单点查询
Code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
typedef long long ll;
const int N = 5e5 + 100;
int n;
ll a[N];
int cmp(ll x, ll y) {
return x > y;
}
int search(ll x) {
int l = 0, r = n;
while (l + 1 < r) {
int mid = (l + r) >> 1;
if (a[mid] <= x) r = mid;
else l = mid;
}
return r;
}
struct SegT {
#define lson x << 1
#define rson x << 1 | 1
#define mid ((l + r) >> 1)
int Min[N << 2], tag[N << 2];
void build(int l, int r, int x) {
if (l == r) {
Min[x] = n + 1;
tag[x] = n + 1;
return;
}
Min[x] = n + 1; tag[x] = n + 1;
build(l, mid, lson); build(mid + 1, r, rson);
}
void pushup(int x) {
Min[x] = min(Min[lson], Min[rson]);
}
void pushdown(int x) {
if (tag[x]) {
Min[lson] = min(Min[lson], tag[x]);
Min[rson] = min(Min[rson], tag[x]);
tag[lson] = min(tag[lson], tag[x]);
tag[rson] = min(tag[rson], tag[x]);
}
}
void modify(int L, int R, int c, int l, int r, int x) {
if (L <= l && r <= R) {
Min[x] = min(Min[x], c);
tag[x] = min(tag[x], c);
return;
}
pushdown(x);
if (L <= mid) modify(L, R, c, l, mid, lson);
if (R > mid) modify(L, R, c, mid + 1, r, rson);
pushup(x);
}
int query(int pos, int l, int r, int x) {
if (l == r) return Min[x];
pushdown(x);
if (pos <= mid) return query(pos, l, mid, lson);
else return query(pos, mid + 1, r, rson);
}
}T;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
scanf("%lld", &a[i]);
sort(a + 1, a + 1 + n, cmp);
for (int i = 1; i <= n; ++i)
ls[i] = a[i];
ll ans = -1;
T.build(1, n, 1);
for (int i = 3; i <= n - 4; ++i) {
ll x = a[i + 1] + a[i + 2] + a[i + 3] + a[i + 4] - a[i] - 1;
int P2 = search(x);
if (P2 >= i) continue;
if (P2 == 1) P2++;
T.modify(P2, i - 1, i, 1, n, 1);
}
for (int i = 2; i < n - 4; ++i) {
int pos = T.query(i, 1, n, 1);
if (pos > n) continue;
ll tot = 0;
for (int j = pos; j <= pos + 4; ++j)
tot += a[j];
ll x = a[i] + a[pos] - 1;
int P1 = search(x);
if (a[P1] > x || P1 >= i) continue;
ans = max(ans, a[P1] + a[i] + tot);
}
printf("%lld\n", ans);
}