Becoder # 16288. 「BZOJ2288 POJ Challenge」生日礼物

题目链接:Becoder or Luogu


首先我们可以先把点给缩一缩,把连续的正数点和连续的负数点分别缩成一个点,比如 1 2 3 -1 -1 1 2 这个东西我们就可以将其缩成 6 -2 3 我们可以发现,求前者的值等于求后者的值,我们就将原序列变为了正负交替的序列。

然后我们就可以开始反悔贪心,将所有数的点全部丢进小根堆里,小根堆的权值是这个点的绝对值,将所有正数的点暂时全部加进答案 ans 并用一个数记录有多少个了,如果这个数大于了 m 我们就开始反悔贪心(这里可能有些人不明白,不过到后面就会明白了,先记着就行。

当一个点是负数,而且它在角落,即左右两边有没有的点,那么我们就可以将其抛弃掉不管它了,反之,那么我们可以分类讨论一下:

  1. 这个点是负数:那么它和它左右两边的点可以是这个形式“正负正”那我们就将这一组合并起来,那正数的点的个数就会减去 1 答案还得加上这个负点,然后我们在把这个新的点丢进堆里面去。

  2. 这个点是正点:那么它和它左右两边的点可以是这个形式“负正负”那我们就将这一组合并起来,那正数的点的个数就会减去 1 答案还得减去上这个正点,然后我们在把这个新的点丢进堆里面去。

  3. 如果这个点是正点,且在最左边或者最右边:那么可以成这个形式“正负”“负正”,很明显我们还是要将其合并起来,然后减去它,再将新点扔进堆里面去,目前选中的点也减去 1

整理一下我们就可以变为,如果这个点满足:是一个负数,左右两边点不全,我们就删除它。如果不满足:答案减去它的绝对值,个数减 1 再合并成一个新点,最后丢进堆里面。

如果还不明白,就结合着代码吧。

#include <queue>
#include <cstring>
#include <algorithm>
#include <iostream>
#define x first
#define y second

using namespace std;

namespace oi{
	using ll = long long;
	using ull = unsigned long long;
	using pii = pair<int, int>;
	using db = double;
	using pll = pair<ll, ll>;
	#define endl '\n'


	inline ll read() {
		char ch = getchar(); ll fu = 0, s = 0;
		while(!isdigit(ch)) fu |= (ch == '-'), ch = getchar();
		while(isdigit(ch)) s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
		return fu ? -s : s;
	}

	template <typename T>
	inline void write(T x, char ch) {
		if(x < 0) putchar('-'), x = -x;
		static int stk[30];
		int tt = 0;
		do stk[++tt] = x % 10, x /= 10; while(x);
		while(tt) putchar(stk[tt--] ^ 48);
		putchar(ch);
	}

	template <typename T>
	inline void write(T x) {
		if(x < 0) putchar('-'), x = -x;
		static int stk[30];
		int tt = 0;
		do stk[++tt] = x % 10, x /= 10; while(x);
		while(tt) putchar(stk[tt--] ^ 48);
	}

	inline void write(char x) {putchar(x);}
};
using namespace oi;
const int MAXN = 1e5 + 10;
int n, a[MAXN], l[MAXN], r[MAXN], m;
int  x, cnt;
ll ans;
bool st[MAXN];

void del(int x) {
	st[x] = true;
	r[l[x]] = r[x];
	l[r[x]] = l[x];
}

void solve() {
	n = read(), m = read();
	for (int i = 1; i <= n; i++) {
		x = read(); if (!x) continue;
		if (1ll * x * a[cnt] > 0) a[cnt] += x;
		else a[++cnt] = x;
	}
	n = cnt;
	cnt = 0;
	priority_queue<pii, vector<pii>, greater<pii>> q;
	for (int i = 1; i <= n; i++) {
		if (a[i] > 0) cnt++, ans += a[i];
		l[i] = i - 1, r[i] = i + 1;
		q.push({abs(a[i]), i});
	}
	while (cnt > m) {
		while (st[q.top().y]) q.pop();
		pii t = q.top(); q.pop();
		int x = t.y;
		if (l[x] != 0 && r[x] != n + 1 || a[x] > 0) {
			cnt--; ans -= abs(a[x]);
			a[x] += a[l[x]] + a[r[x]];
			del(l[x]), del(r[x]);
			q.push({abs(a[x]), x});
		} else {
			del(x);
		}
	}
	write(ans, '\n');
}

signed main() {
	// freopen("test.in", "r", stdin);
	// freopen("test.out", "w", stdout);

	int T = 1;
	// T = read();
	while(T--) solve();
	return 0;
}
posted @   wh2011  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示