码迷,mamicode.com
首页 > 其他好文 > 详细

[Luogu] CF557C Arthur and Table

时间:2020-11-17 12:51:13      阅读:9      评论:0      收藏:0      [点我收藏+]

标签:tab   max   最大   limits   define   ++   超过一半   getch   大于   

\(Link\)

Description

有一张桌子,有\(n\)个腿。第\(i\)根腿的长度是\(l_i\)?。

现在要拿掉一些腿,使得桌子稳定,拿掉第\(i\)根腿需要\(d_i\)的能量。

稳定的条件是,假如拿掉若干条腿之后,桌子还有\(k\)个腿,那么长度最长的腿的数目要超过一半。比如桌子有\(5\)根腿,那么至少要有\(3\)根腿是最长的。另外,只有一根腿的桌子是稳定的,两个腿的桌子想要稳定,必需长度是一样的。

你的任务是拿掉若干腿,使得桌子稳定,并且所消耗的能量要最少。

Solution

我们可以枚举桌腿最长的长度是什么,设其为\(l_{mx}\),然后有\(t\)根的\(l_i=l_{mx}\),那么保留的最大能量就是\(\sum\limits_{l_i=l_{mx}}d_i\),加上长度小于它的桌腿中,选最大的\(t-1\)根的能量之和(因为要最大化保留的,才能最小化消耗的)。

考虑我们从小到大枚举\(l_{mx}\),处理这个长度后再把所有满足\(l_i=l_{mx}\)\(d_i\)加入当前序列中,那么现在要解决的问题就是要动态维护序列前\(t-1\)大之和。而对顶堆可以很方便解决这类动态求第\(k\)大或前\(k\)大的问题。

对顶堆就是维护两个堆,一个大根堆\(q_1\),一个小根堆\(q_2\),然后保证\(q_2\)里的所有元素都大于\(q_1\)里的,不满足就不断一个\(pop()\),一个\(push(top())\)

我们再保证\(q_2.size()=t-1\),那这道题的前\(t-1\)大之和就是\(q_2\)内元素之和了。

这个是很难被卡的,因为单次操作次数取决于\(|t_i-t_{i-1}|\),最大也就是\(n\),复杂度其实和线段树一样也是\(nlog(n)\)

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

int n, m, sz[100005], l[100005], d[100005];

vector < int > g[100005];

ll mx, s0, sum, s[100005];

priority_queue < int > q1;
priority_queue < int, vector < int > , greater < int > > q2; 

int read()
{
	int x = 0, fl = 1; char ch = getchar();
	while (ch < ‘0‘ || ch > ‘9‘) { if (ch == ‘-‘) fl = -1; ch = getchar();}
	while (ch >= ‘0‘ && ch <= ‘9‘) {x = (x << 1) + (x << 3) + ch - ‘0‘; ch = getchar();}
	return x * fl;
}

int main()
{
	n = read();
	for (int i = 1; i <= n; i ++ )
		l[i] = read(), m = max(m, l[i]);
	for (int i = 1; i <= n; i ++ )
		d[i] = read(), sum += (ll)d[i];
	for (int i = 1; i <= n; i ++ )
	{
		g[l[i]].push_back(d[i]);
		s[l[i]] += (ll)d[i];
		sz[l[i]] ++ ;
	}
	for (int i = 1; i <= m; i ++ )
	{
		if (!sz[i]) continue;
		ll cnt = s[i];
		while ((int)q2.size() != sz[i] - 1)
		{
			if ((!q1.size()) && (!q2.size())) break;
			while (q2.size() < sz[i] - 1)
			{
				int x = q1.top();
				q1.pop();
				q2.push(x);
				s0 += x;
			}
			while (q2.size() > sz[i] - 1)
			{
				int x = q2.top();
				q2.pop();
				q1.push(x);
				s0 -= x;
			}
		}
		mx = max(mx, cnt + s0);
		for (int p = 0; p < (int)g[i].size(); p ++ )
		{
			int x = g[i][p];
			if (q1.size() && x > q1.top()) q2.push(x), s0 += x;
			else q1.push(x);
		}
	}
	printf("%lld\n", sum - mx);
	return 0;
}

[Luogu] CF557C Arthur and Table

标签:tab   max   最大   limits   define   ++   超过一半   getch   大于   

原文地址:https://www.cnblogs.com/andysj/p/13961428.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!