题目链接: Boboniu Chats with Du
大致题意:
给你n个数字, 让你给这n个数字进行合理排序, 使得结果这n个数字之和最大.
条件: 如果某个位置i出现了大于m的数字, 则接下来的d个数字将不进行加和计算(如果后面不足d个数字则忽略到结束).
解题思路:
贪心即可.
我们将数字整体分为两类, a类为大于m的数字, b类为小于m的数字. 我们可以知道答案至少为所有b类数字之和.
倘若我们此时选择1个a类数字, 则我们一定要选最大的a类数字, 且一定要把他放在最后一位是最优的(因为这样不会导致后续d个数字失效).
倘若我们要选择2个a类数字, 我们也是要选择尽可能大的两个a类数字, 一个仍是放在最后一位, 另一个如果放在i位置, 则后面d个数我们最理想的是都放a类数字, 如果剩余的a类数组不足d个, 则我们需要放弃尽可能小的几个b类数字, 让其在后d位处.
此时我们就可以得出结论: 假设我们选择了num个a类数(剩下的a类数我们选择直接放弃), 则我们需要为其中的num-1个数后安排(num-1)*d个a类或b类数(a类优先, 其次b类较小的优先).
AC代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1E5 + 10;
int a[N], b[N], inda, indb;
ll s1[N], s2[N]; //前缀和
int main()
{
int n, d, m; cin >> n >> d >> m;
for (int i = 1; i <= n; ++i) {
int x; scanf("%d", &x);
if (x > m) a[++inda] = x;
else b[++indb] = x;
}
sort(a + 1, a + 1 + inda, greater<>());
sort(b + 1, b + 1 + indb);
for (int i = 1; i <= inda; ++i) s1[i] = s1[i - 1] + a[i];
for (int i = 1; i <= indb; ++i) s2[i] = s2[i - 1] + b[i];
ll res = s2[indb]; //选择所有小于m的情况(不选择a类数的情况)
for (int i = 0; i < inda; ++i) { //选择i+1个a类数的情况
if (i * (d + 1) + 1 > n) break; //表明此时我们所选择的所有数字已经大于n个, 情况不存在
int need = i * d; //需要的填充物
int leave = inda - (i + 1); //a类能提供的填充物数量
need = max(need - leave, 0); //避免是负数情况
ll temp = s2[indb] - s2[need] + s1[i] + a[i + 1];
res = max(res, temp);
}
cout << res << endl;
return 0;
}