链接
知识点
前缀和,枚举
思路
首先,我们想到了一种贪心的解法,每次删除价值和更小的两个宝石或者删除价值最大的宝石,根据哪种操作可以删除价值更小的宝石。然而,这种方法甚至在示例上都不适用,我们需要更优的解法。
注意到操作的顺序并不重要:删除两个最小的宝石然后再删除最大的宝石与先删除最大的宝石然后再删除两个最小的宝石的操作是相同的。因此,我们可以假设删除了最大宝石的操作次数为m,当我们删除最大宝石时,剩下的宝右组成的数组就是从中删除了2m个最小宝石和(k一m)个最大宝石的宝石数组。
然后,对原始数组进行排序不会影响结果,因为最小宝石始终在数组的开头,最大宝石则在数组的末尾。也就是排序后,每次操作要么删除左边的两个元素,要么删除右边的一个元素。因此,如果我们删除2m个最小宝石和(k一m)个最大宝石,则剩余的元素组成的段在排序后的数组中从位置(2m+1)到位置(n-(k-m)),可以从左到石遍历m,使用前缀和计算其总和。
代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 2e5+10;
ll a[N],prefix[N];
int main(){
int t;
cin>>t;
while(t--){
int n,k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
sort(a+1,a+n+1);
for(int i=1;i<=n;i++){
prefix[i] = prefix[i-1] + a[i];
}
ll ans = 0;
int pos = 0;
while(k>=0){
ans = max(ans,prefix[n-k] - prefix[pos]);
pos += 2;
k--;
}
cout<<ans<<endl;
}
return 0;
}