Liebig's Barrels CodeForces #985C 题解[C++]

题目来源


http://codeforces.com/contest/985/problem/C

题意分析


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 v j 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. | v x v y | l   f o r   a n y   1 x n   a n d   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   a n d   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 ≤ 109) — 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 | v x v y | l   f o r   a n y   1 x n   a n d   1 y n .

Sample Input

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

input

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 块木板, 要求组成 n 个木板数为 k 的木桶. 木桶的容积等于木桶的最短木板. 要求任意两个木桶间的容积差小于给定的阈值 l , 使得k个木桶的容积和最大.

解题思路


这题乍看上去像是桶排序, 然而其实并不是这样.

首先我们考虑题目的约束条件, 即任意木桶容积( 最短木板 )差小于阈值. 那么所有木桶的最短木板只可能出现在最短的这批木板中: [ m i n , m i n + l ] .

因此记落在 [ m i n , m i n + l ] 中的木板数为: m . 我们接下来分两种情况讨论:
1. m < k , 这种情况下不可能满足任意木桶间容积差小于 l , 输出0返回;
2. m >= k , 这时我们需要从 m 块木板中选出 k 块分别作为每个木桶的最短板. 为使木桶的容积和最大, 我们要尽可能的把比较短的木板凑在一起形成同一个木桶, 这样稍长些的木板就可以被选为其它木桶的最短板. 所以这里使用贪心策略:
优先用当前(未使用过的)最短的木板和比它长一点的木板构成木桶, 其中最短的木板作为该木桶的最短板, 直到


- 已经构成了一整个木桶;
- 或剩下的木板数恰好等于未确定最短板的木桶数;

根据以上的分析很容易能写出实现. 但在这里我们还可以进行优化. 因为我们只需要找出 [ m i n , m i n + l ] 里的木板, 所以我们的任务并不用排序整个n*k, 可以利用变形的堆排序.

建立一个小根堆, 依次弹出堆顶保存. 直到发现当前的堆顶已大于 m i n + l 为止.

代码实现


#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

vector<long> entry;
int total;

void insert_heap(long current, int low, int high)
{
    int small = 2 * low + 1;
    while (small <= high) {
        if (small < high&&entry[small] > entry[small + 1]) small++;
        if (current <= entry[small]) break;
        else {
            entry[low] = entry[small];
            low = small;
            small = 2 * low + 1;
        }
    }
    entry[low] = current;
}

void build_heap()
{
    for (int low = total / 2 - 1; low >= 0; low--) {
        long current = entry[low];
        insert_heap(current, low, total - 1);
    }
}

int main()
{
    long n, k, threshold, temp;
    long long tempAns = 0;
    scanf("%ld%ld%ld", &n, &k, &threshold);
    total = n*k;
    for (int i = 0; i <total; i++) {
        scanf("%ld", &temp);
        entry.push_back(temp);
    }

    build_heap();

    long last_unsorted, current, sst;
    sst = entry[0];
    long lst = sst + threshold;

    for (last_unsorted = total - 1; last_unsorted > 0; last_unsorted--) {
        current = entry[last_unsorted];
        if (entry[0] > lst) break;
        entry[last_unsorted] = entry[0];
        insert_heap(current, 0, last_unsorted - 1);
    }

    if (entry[0] <= lst) last_unsorted = -1;

    if (total - last_unsorted - 1 < n) {
        printf("0\n");
        return 0;
    }

    int j, buckets = 0;
    long long ret = 0;

    int p = total - 1;
    for (int i = 1; i <= n; i++) {
        ret += entry[p--];
        for (int j = 1; j <= k - 1; j++) {
            if ((p - last_unsorted + i) <= n) break;
            else p--;
        }
    }
    printf("%I64d\n", ret);
    return 0;
}

代码表现


985-c

猜你喜欢

转载自blog.csdn.net/wayne_mai/article/details/80536465