最大和(滑动窗口BT版--窗口外围)

26 篇文章 0 订阅
26 篇文章 0 订阅

时间限制: 2 Sec  内存限制: 256 MB

题目描述

小鸿给你一个数组a1,a2,...,an,其中所有元素都是不同的。

你必须对其进行k次操作。在每个操作中,你需要做以下两个操作中的一个(每次任选其中之一即可):

1.找到数组中的两个最小元素,并删除它们;
2.找到数组中的最大元素,并删除它。

小鸿想计算出k次操作后,所得数组的最大元素之和。但这对小鸿来说太难了,你能帮帮他吗?

输入

第一行包含一个整数 t (1≤t≤104) — 测试用例的数量。

每个测试用例由两行组成:
第一行包含两个整数 n和 k (3≤n≤2⋅105; 1≤k≤99999; 2k<n) — 元素和操作的数量。
第二行包含n个整数 a1,a2,...,an (1≤ai≤109;所有 ai不同) — 数组的元素。

数据保证n的总和不超过2⋅105。

输出

对于每个测试用例,输出一个整数 — 结果数组中元素的最大可能总和。

样例输入:

6
5 1
2 5 1 10 6
5 2
2 5 1 10 6
3 1
1 2 3
6 1
15 22 12 10 13 11
6 2
15 22 12 10 13 11
5 1
999999996 999999999 999999997 999999998 999999995

样例输出 :

21
11
3
62
46
3999999986

提示

在第一个测试用例中,使用第一个操作会产生以下结果:

*两个最小值为 1和 2;删除它们会使数组保留为 [5,10,6],总和为 21;

*最大值为 10;删除它会使数组保留为 [2,5,1,6],总和为 14.

很明显,21是最好的答案。

在第二个测试用例中,最优选择是一次删除两个最小值,一次删除最大值,这样就能得到11。

代码献上(滑动窗口BT版--窗口外围):

#include<iostream>
#include<algorithm>

using namespace std;

#define int long long

const int N = 2e5 + 10;

int q[N];

void qw()
{
	int n, k; cin >> n >> k;

	int num = 0;
	for (int a = 1; a <= n; a++)
	{
		cin >> q[a];
		num += q[a];       //求和
	}
	sort(q + 1, q + 1 + n); //排序

	for (int a = 1; a <= n; a++)q[a] += q[a - 1];//前缀和

	int res = 1e18;//最大值

	int cnt = 0;//最小值

	for (int a = 0; a < k; a++)
	{
//分成两部分保存最大的中间值
//前部分和--AA=q[cnt]
//后部分和--BB=q[n]-q[n-k-a]
//前后相加之和res最小则变相得到中间最大值
//类似于外围的滑动窗口

		if (res > q[cnt] + q[n] - q[n - k - a]) //判断是否比保存的最小值还小如此就变得更小一直到最小
			res = q[cnt] + q[n] - q[n - k + a]; //最小值的更新
		            cnt  += 2;                  //前面加2后面减1
	}
             	cout << num - res << endl;      //输出中间最大值
}

signed main()
{
	int v; cin >> v;
//多组样例输入

	while (v--)
	{
		qw();
//执行函数

	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值