【Codeforces】Codeforces Round #831 (Div. 1 + Div. 2) C. Bricks and Bags | 贪心

364 阅读2分钟

本文已参与「新人创作礼」活动, 一起开启掘金创作之路。

题目链接

Problem - 1740C - Codeforces

题目

image.png

题目大意

nn 块砖,编号从 11nn。第 ii 块砖的重量为 aia_i。初始有 3 个空袋子分别以 1,2,31,2,3 标号。

Pak Chanek 把 nn 块砖分别放进 3 个空袋子里,需要保证每个袋子里至少有一块砖。Bu Dengklek 从 3 三个袋子里分别取出一块砖,记从第 1 个袋子里取出来的砖的重量为 w1w_1,从第 2 个袋子里取出来的砖的重量为 w2w_2,从第 3 个袋子里取出来的砖的重量为 w3w_3,则得分为 w1w2+w2w3|w_1−w_2|+|w_2−w_3|

Bu Dengklek 想最小化得分,如果 Pak Chanek 以最佳方式往三个袋子里放砖,最终可能的最大分数是多少?

思路

如果我们把所有砖的重量排序并去重,将排序去重后的重量记为 b1,b2,...,bmb_1,b_2,...,b_m,则:

  • 如果 m==1m==1,则答案为 0。
  • 如果 m==2m==2,则答案为 2×(b2b1)2\times(b_2-b_1)。即我们可以把出现次数更多的砖放进 1,3 袋子里,另一种砖放在第二个袋子里。

接下来我们讨论 m3m\ge 3 的情况。

如果我们把 b1b_1 放在第一个袋子里,bmb_m 放在第三个袋子里,其他元素放在中间,则最终的答案就是 bmb1b_m-b_1。显然以下两种情况算出来的答案会更大: image.png 前者的答案是 bmb1+bmbm1b_m-b1+b_m-b_{m-1},即将b1b_1 放在第 1 个袋子里,bmb_m 放在第 2 个袋子里,其他元素放在最后。后者的答案是 bmb1+b2b1b_m-b1+b_2-b_1,即将b1b_1 放在第 2 个袋子里,bmb_m 放在第 3 个袋子里,其他元素放在第 1 个袋子里。

这样是否就能取得最优解呢?如果把 b1b_1 放在第 1 个袋子里,把 bib_ibmb_m 都放在中间,把 b2b_2bi1b_{i-1} 放在最后,就能取到答案 bib1+bibi1b_i-b_1+b_i-b_{i-1}。如果 bibi1b_i-b_{i-1} 对答案造成的正面影响大于 bib_ibmb_m 小造成的负面影响,bib1+bibi1b_i-b_1+b_i-b_{i-1} 就是更优的解。第二种情况与之类似。

所以我们需要枚举每块砖作为拐点的情况,取最优解输出答案。

代码

#include <bits/stdc++.h>
#define nnn printf("No\n")
#define yyy printf("Yes\n")
using namespace std;
using LL=long long;
typedef pair<int,int> PII;
const int N=500001;
int n,m,k;
LL a[N],b[N];
int solve()
{
	scanf("%d",&n);
	LL ans=0;
	for (int i=1;i<=n;++i) scanf("%lld",&a[i]);
	sort(a+1,a+1+n);
	m=0;
	for (int i=1;i<=n;++i)
		if (a[i]!=a[i-1]) b[++m]=a[i];
	if (m==1) return printf("0\n"),0;
	if (m==2) return printf("%lld\n",(b[2]-b[1])*2),0;
	ans=b[m]-b[1];
	for (int i=1;i<m;++i)
		ans=max(ans,b[m]-b[i]+b[i+1]-b[i]);
	for (int i=m;i>1;--i)
		ans=max(ans,b[i]-b[1]+b[i]-b[i-1]);
	printf("%lld\n",ans);
	return 0;
}
int main()
{
	int T=1;
	for (scanf("%d",&T);T--;) solve();
	return 0;
}