Problem

来源:互联网 发布:知乎机构号注册流程 编辑:程序博客网 时间:2024/06/05 08:02

Arthur and Table

Arthur has bought a beautiful big table into his new flat. When he came home, Arthur noticed that the new table is unstable.In total the table Arthur bought has n legs, the length of the i-th leg is li.Arthur decided to make the table stable and remove some legs. For each of them Arthur determined number di — the amount of energy that he spends to remove the i-th leg.A table with k legs is assumed to be stable if there are more than half legs of the maximum length. For example, to make a table with 5 legs stable, you need to make sure it has at least three (out of these five) legs of the maximum length. Also, a table with one leg is always stable and a table with two legs is stable if and only if they have the same lengths.Your task is to help Arthur and count the minimum number of energy units Arthur should spend on making the table stable.

Input

The first line of the input contains integer n (1 ≤ n ≤ 105) — the initial number of legs in the table Arthur bought.The second line of the input contains a sequence of n integers li (1 ≤ li ≤ 105), where li is equal to the length of the i-th leg of the table.The third line of the input contains a sequence of n integers di (1 ≤ di ≤ 200), where di is the number of energy units that Arthur spends on removing the i-th leg off the table.

Output

Print a single integer — the minimum number of energy units that Arthur needs to spend in order to make the table stable.

Examples

Input21 53 2Output2Input32 4 41 1 1Output0Input62 2 1 1 3 34 3 5 5 2 1Output8

这题在Codeforces上的标签有brute forcedata structuresdp以及greedy。一开始做以为是单纯的区间dp,想破头也没想明白。后来看题解也看得十分懵,自行设计了“再次使用sort(),直接将代价较小的桌腿置于数组前部,从而贪心地锯断这些桌腿”的方案。自觉十分完美,同时判断次数较少,最后结果是超时。我非常懊恼,最终还是强行把桶排序枚举的贪心策略给看明白了,解决了这道题。

简单地说,这题就是要找到一种长度 len,这种长度的桌腿有 x 根。将 len 作为最终留下的最长桌腿长度,将长度大于 len 的桌腿全部移除,长度等于 len 的全部保留,再额外保留 x1 根长度小于 len 的任意桌腿(如果长度小于 len 的桌腿有这么多的话),同时确保额外保留的 x1 根桌腿的锯断代价是长度小于 len 的桌腿中代价最大的那一部分。

假设我们规定最长桌腿长度 len=l,那么按照上述条件操作,可以确保让桌子以长为 l 的桌腿保持平衡的代价是最小的。亦即我们要在尽量少锯桌腿的情况下保持桌子的平衡,若非锯不可,我们也选择代价小的来锯断。

刚才假设的是一种定长 len=l。那么对于不同的 len,结果自然会有所不同。这就需要从桌子的最短桌腿枚举到最长桌腿,看看用哪种桌腿来保持平衡可以令总代价最小。

这一题的关键在于 k[1,200] 的对代价的枚举。
考虑如下样例(Codeforces test 5):

桌腿长度 5 6 7 14 15 16 17 19 19 19 代价 195 70 54 67 140 183 56 25 132 186

首先可以看出,必须令 len=19 才可能获得最小代价;而为使代价最小,需要将红色高亮所示的5条桌腿锯断。而本例中最小的代价就是这五个代价之和:387。

如何得出最小代价呢?
len=5 枚举至 len=19 的过程易于理解,主要是在长度小于19的桌腿中保留代价最大的两个桌腿。为达到这一效果,我们需要记录所有长度小于19的桌腿对应的代价,然后令 k[1,200]k 表示对代价的枚举,从大到小。这样就可以完成按代价从大到小的顺序检查桌腿,保留代价最大的 x1 条桌腿的过程,从而得出最小代价。

注:代码中的枚举过程显示,对 len=19 的枚举要进行三次,分别对应三个长度为19的桌腿。但最后能确保得到最小代价。原因是:第一次枚举表示三个长为19的桌腿全部保留,额外保留两条长度较短的桌腿;第二次枚举表示保留两个长为19的桌腿,额外保留两条长度不大于19的桌腿;第三次枚举表示保留第三条长为19的桌腿,额外保留两条长度不大于19的桌腿。可以想象,第一次枚举共保留了5条桌腿(长度分别为5,16,19,19,19),第二次枚举共保留了4条桌腿(长度分别为5,19,19,19),第三次枚举保留了三个长为19的桌腿。显然,只有第一次枚举保留的桌腿最多,才可能取得最小代价。

#include <algorithm>#include <iostream>#include <cstdio>#include <cstring>using namespace std;const int maxn = 1e5+4, INF = 0x7fffffff;int ocur[maxn], allCost[maxn], sumOcur[maxn], sumCost[maxn], barrel[204];// ocur[]:每种长度的桌腿总数;// allCost[]:每种长度的桌腿的代价总和;// sumOcur[]:桌腿出现次数的前缀和;// sumCost[]:桌腿代价总和的前缀和;// barrel[]:对代价的桶排序。struct leg{    int len, cost;    bool operator < (const leg &a)const{        return len < a.len;    }} legs[maxn];int main(){#ifdef TESTfreopen("test.txt", "r", stdin);#endif // TEST    int n;    while(cin >> n){        memset(ocur, 0, sizeof(ocur));        memset(allCost, 0, sizeof(allCost));        memset(sumOcur, 0, sizeof(sumOcur));        memset(sumCost, 0, sizeof(sumCost));        memset(barrel, 0, sizeof(barrel));        for(int i = 1; i <= n; i++){            scanf("%d", &legs[i].len);            ocur[legs[i].len]++;// 记录某种长度的桌腿总数。        }        for(int i = 1; i <= n; i++){            scanf("%d", &legs[i].cost);            allCost[legs[i].len]+=legs[i].cost;// 记录某种长度的桌腿的总代价。        }        sort(legs+1, legs+1+n);// 按桌腿长度进行排序。        int maxLen = legs[n].len;// 记录桌腿最大长度,用于规定后续枚举的上界。        for(int i = 1; i <= maxLen; i++){// 构造前缀和。            sumOcur[i] = sumOcur[i-1] + ocur[i];            sumCost[i] = sumCost[i-1] + allCost[i];        }        int result = INF;        for(int i = 1; i <= n; i++){// 枚举最终的最长桌腿长度。            int tempRes = sumCost[maxLen] - sumCost[legs[i].len];// 去掉大于当前枚举值的桌腿所需的代价。            int anotherLeftPart = ocur[legs[i].len] - 1;// 需要格外留下的最大桌腿数量。            for(int k = 200; k >= 1; k--){// 枚举长度小于当前桌腿长度的代价。                if(barrel[k] > 0){                    if(barrel[k] <= anotherLeftPart)                        anotherLeftPart -= barrel[k];                    else{                        tempRes+=k*(barrel[k] - anotherLeftPart);                        anotherLeftPart = 0;                    }                }            }            result = min(result, tempRes);            barrel[legs[i].cost]++;// 延迟添加当前桌腿的代价值,确保每次枚举代价时所检查的代价值都属于“长度小于等于当前桌腿”的桌腿的代价。        }        cout << result << endl;    }    return 0;}
原创粉丝点击