原题:
C. Liebig’s Barrels
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You have m = n·k wooden staves. The i-th stave has length ai. You have to assemble n barrels consisting of k staves each, you can use any k staves to construct a barrel. Each stave must belong to exactly one barrel.
Let volume vj of barrel j be equal to the length of the minimal stave in it.
You want to assemble exactly n barrels with the maximal total sum of volumes. But you have to make them equal enough, so a difference between volumes of any pair of the resulting barrels must not exceed l, i.e. |Vx -Vy| ≤ l for any 1 ≤ x ≤ n and 1 ≤ y ≤ n.
Print maximal total sum of volumes of equal enough barrels or 0 if it’s impossible to satisfy the condition above.
Input
The first line contains three space-separated integers n, k and l (1 ≤ n, k ≤ 10^5, 1 ≤ n·k ≤ 10^5, 0 ≤ l ≤ 10^9).
The second line contains m = n·k space-separated integers a1, a2, …, am (1 ≤ ai ≤ 10^9) — lengths of staves.
Output
Print single integer — maximal total sum of the volumes of barrels or 0 if it’s impossible to construct exactly n barrels satisfying the condition |Vx - Vy| ≤ l for any 1 ≤ x ≤ n and 1 ≤ y ≤ n.
Examples
input
4 2 1
2 2 1 2 3 2 2 3
output
7
input
2 1 0
10 10
output
20
input
1 2 1
5 2
output
2
inputCopy
3 2 1
1 2 3 4 5 6
output
0
Note
In the first example you can form the following barrels: [1, 2], [2, 2], [2, 3], [2, 3].
In the second example you can form the following barrels: [10], [10].
In the third example you can form the following barrels: [2, 5].
In the fourth example difference between volumes of barrels in any partition is at least 2 so it is impossible to make barrels equal enough.
中文:
给你n×k个板子,每个板子长度为ai,现在让你把这n×k个板子分成n组,每组k个,每组当中取长度最小的值求和,且要求在这些组当中,任意取两组,两个组中各自的最小值相差不超过l,现在问你这个和最大是多少?
代码:
#include<iostream>
#include<limits>
#include<vector>
#include<string>
#include<sstream>
#include<algorithm>
using namespace std;
typedef long long ll;
int n, k, l;
ll a[100001];
int main()
{
ios::sync_with_stdio(false);
while (cin >> n >> k >> l)
{
int ter = n*k;
for (int i = 1; i <= ter; i++)
cin >> a[i];
sort(a + 1, a + 1 + ter);
int ind = ter;
for (int i = 2; i <= ter; i++)
{
if (a[i] - a[1]>l)
{
ind = i - 1;
break;
}
}
ll ans = 0;
if (n == 1)
{
cout << a[1] << endl;
continue;
}
if (ind<n)
{
cout << 0 << endl;
continue;
}
if (k == 1)
{
for (int i = 1; i <= ind; i++)
ans += a[i];
cout << ans << endl;
continue;
}
int res = ter - ind, pre = ind, flag = 1;
for (int i = ind; i >= 1;)
{
if (res>0)
{
if (res >= (k - 1))
{
res -= (k - 1);
ans += a[i];
i--;
pre = i;
}
else
{
while ((pre - i + 1) + res<k)
i--;
ans += a[i];
flag = 0;
res = 0;
}
}
else
{
if (flag != -1)
{
if (flag!=0)
i++;
flag = -1;
}
i -= k;
if (i<1)
break;
ans += a[i];
}
}
cout << ans << endl;
}
return 0;
}
思路:
要求所有组中最小值的和最大,听起来像是二分,贪心可以解决。那就是要让每组当中的最小值从最大的值开始选取即可。
首先从小到大排序,找到最后一个小于最小值加上l的下标ind,从ind向前依次取值作为每一组当中的最小长度,同时判断在下标ind后面是否有元素,如果有,尽量选取k个,与前面选取到的最小长度组成一组。
如果ind后面没有元素了,那么就一次从后向前组成一组即可。
例如
4 2 2
1 2 2 3 3 4 5 6
上面序列是排好序的,最小值是1,加上l=2以后是3。
那么ind值等于5
从ind向前依次选取最小元素与ind后面的值组成一组
[3,4]
[3.5]
[2,6]
4,5,6都被选抽走后,依次从后往前组成组即可
[1,2]
结果为9