题解:P10093 [ROIR 2022] 礼物 (Day 2)

题意简述

给定 \(k\) 和一个长度为 \(n\) 的序列 \(a\),定义一个区间 \([l,r](l\leq r\land r-l+1\geq k)\) 的权值为 \(a[l,r]\) 中除去前 \(k\) 大的元素和。求出最大权值。

对于所有数据,\(1\leq n\leq 2\times 10^5\)\(0\leq k\leq \min(100,n)\)\(-10^9\leq a_i\leq 10^9\)

题解

有点乱炖的意思了。

对这种权值的一类刻画方式就是枚举某个特定的值。在本题中,容易想到枚举第 \(k\)\(a_p\)

思考怎样的区间 \(l\leq p\leq r\) 会使得 \(a_p\) 为该区间的第 \(k\) 大。对于排序网络相关的问题,考虑构造 \(0/1\) 序列。具体来说,构造 \(0/1\) 序列 \(b_i=[a_i\geq a_p]\),那么区间 \([l,r]\) 合法的充要条件就是 \(\sum_{i=l}^r b_i=k\)。并且容易注意到,一个区间的权值,转化为了所有为 \(0\) 的位置对应的元素和

注意到 \(k\) 很小,考虑从这里入手去做一些偏暴力的东西。一个自然的想法就是分别找到 \(a_p\) 左右侧的 \(k-1\)\(1\),得到最多 \(2k-1\)\(1\),那么我们就可以 \(O(k)\) 地枚举出区间和为 \(k\) 的所有合法区间。

假装我们已经可以找到这些 \(1\),然后正在枚举某个区间和为 \(k\) 且两端都是 \(1\) 的区间 \([l,r]\),这时候我们肯定是保证区间和不变的基础上,尝试拓展区间的两端到 \([l',r']\)。 显然可以贪心,以左端点为例,设 \(l\) 前面最近的 \(1\) 的位置为 \(l_1\),那么我们就要求出

\[\begin{align*} & \min_{l'=l_1+1}^l\sum_{i=l'}^l a_i \\ =& \min_{l'=l_1+1}^l\{s_l-s_{l'-1}\} \\ =& s_l-\min_{l'=l_1+1}^l\{s_{l'-1}\} \end{align*} \]

其中 \(s\)\(a\) 的前缀和序列。对 \(s\) 建立 ST 表即可 \(O(1)\) 求出上面的东西,右端点同理。还有一部分是 \([l,r]\)\(0\) 的位置对应的元素和,这个直接枚举区间的过程中存一下就行了。把这些值全部加起来就是这个区间能得到的最大权值,和答案取 \(\max\) 即可。

最后就是怎么找到 \(a_p\) 左右侧的 \(k-1\)\(1\)。这个也很典。对 \(a\) 建立一个链表,然后从小到大扫每个元素,直接在链表上分别跳 \(k-1\) 次前驱和后继就是我们要找的 \(1\),最后在链表中把当前元素删掉即可。

时间复杂度为 \(O(n\log{n}+nk)\)

实现 & 代码

细节还是有点多的。

首先把 \(k=0\) 特判掉,枚举端点,用建出来的 ST 表就可以做,注意这种 case 答案不能和 \(0\)\(\max\),因为 \(l\leq r\),我们不能不选。

\(k>0\) 的情况在枚举区间时可能会有一些边界问题,改成左右各找 \(k\)\(1\) 可以实现得更优雅一些。

应该没啥了,贴个代码。

#include <iostream>
#include <algorithm>

using namespace std;

#define lowbit(x) ((x) & -(x))
#define chk_min(x, v) (x) = min((x), (v))
#define chk_max(x, v) (x) = max((x), (v))
typedef long long ll;
typedef pair<int, int> pii;
const int N = 2e5 + 5, LOGN = 18 + 5, K = 205;
const ll INF = 1e16;

int n, k, a[N], lg2[N];
int szc, c[K];
int top, stk[K];
pii b[N];
ll ans = -INF, s[N];

struct ST {
	ll mx[LOGN][N], mn[LOGN][N];
	void init() {
		for (int i = 0; i <= n; ++i) mx[0][i] = mn[0][i] = s[i];
		for (int i = 1; i <= lg2[n + 1]; ++i)
			for (int j = 0; j <= n - (1 << i) + 1; ++j)
				mx[i][j] = max(mx[i - 1][j], mx[i - 1][j + (1 << (i - 1))]),
				mn[i][j] = min(mn[i - 1][j], mn[i - 1][j + (1 << (i - 1))]);
	}
	ll query_mx(int l, int r) {
		int k = lg2[r - l + 1];
		return max(mx[k][l], mx[k][r - (1 << k) + 1]);
	}
	ll query_mn(int l, int r) {
		int k = lg2[r - l + 1];
		return min(mn[k][l], mn[k][r - (1 << k) + 1]);
	}
} st;

int pos[N], id[N];
struct List {
	int tot, head, tail, prv[N], nxt[N], val[N];
	void init() {
		head = 1, tail = 2; tot = 2;
		nxt[head] = tail, prv[tail] = head;
		id[head] = 0, id[tail] = n + 1;
	}
	void insert(int p, int v) {
		int q = ++tot; val[q] = v;
		nxt[q] = nxt[p], prv[nxt[p]] = q;
		prv[q] = p, nxt[p] = q;
	}
	void del(int p) { prv[nxt[p]] = prv[p], nxt[prv[p]] = nxt[p]; }
} lt;

void preproc() {
	lg2[1] = 0;
	for (int i = 2; i <= n + 1; ++i) lg2[i] = lg2[i >> 1] + 1;
}

int main() {
	ios::sync_with_stdio(false); cin.tie(nullptr);
	cin >> n >> k; lt.init();
	int last = lt.head;
	for (int i = 1; i <= n; ++i) {
		cin >> a[i]; b[i] = { a[i], i };
		s[i] = s[i - 1] + a[i];
		lt.insert(last, a[i]), last = pos[i] = lt.tot, id[lt.tot] = i;
	}
	preproc(), st.init();
	sort(b + 1, b + n + 1);
	for (int i = 1; i <= n; ++i) {
		if (!k) { chk_max(ans, s[i] - st.query_mn(0, i - 1)); continue; }
		int p = pos[b[i].second];
		stk[++top] = p, p = lt.prv[p];
		for (int cnt = 1; cnt <= k && p; ++cnt, p = lt.prv[p]) stk[++top] = p;
		szc = -1;
		while (top) c[++szc] = stk[top--];
		p = lt.nxt[pos[b[i].second]];
		for (int cnt = 1; cnt <= k && p; ++cnt, p = lt.nxt[p]) c[++szc] = p;
		--szc;
		ll sum = 0;
		for (int j = 1; j <= k; ++j) sum += a[id[c[j]]];
		for (int j = 1; j <= szc - k + 1; ++j) {
			int l = id[c[j - 1]], r = id[c[j]] - 1;
			ll lmx = s[r] - st.query_mn(l, r);
			l = id[c[j + k - 1]], r = id[c[j + k]] - 1;
			ll rmx = st.query_mx(l, r) - s[l];
			ll md = s[id[c[j + k - 1]]] - s[id[c[j]] - 1] - sum;
			chk_max(ans, lmx + rmx + md);
			sum += a[id[c[j + k]]] - a[id[c[j]]];
		}
		lt.del(pos[b[i].second]);
	}
	cout << ans;
	return 0;
}
posted @ 2025-02-03 20:17  P2441M  阅读(21)  评论(0)    收藏  举报