2015-07-14 12:50:34
【传送门】
总结:前4题都不难。最后一次涉及字符串,待补...
A题、B题不说了。
C题:排序,枚举
题意:有一个n个脚的桌子,每根脚有长度和拆除它的需要的能量,为了使桌子平衡,你要拆除一些脚。平衡的条件是最长的脚的数量 > k / 2(k为剩余的脚的总数量),要求求出所需的最少总能量。(n <= 10^5 ,脚的长度 <= 10^5 ,拆除脚需要的能量 <= 200)
思路:首先将所有脚按照长度进行排序,然后枚举最后剩下的脚中的最大长度,那么显然比枚举值长的脚要拆除,因为还要使得桌子平衡,所以先统计出有多少脚的长度等于枚举的长度,设其数量为cnt,先拆除比枚举长度更长的脚,然后统计剩下的脚的数量M,那么还需要拆除的脚的数量就是ned = max(0,M-(2*cnt-1)),当然我们要找出所需能量最少的ned个脚,然后将其拆除。找的过程可以这样:由于能量的范围很小,我们可以预先统计出每个能量有多少根脚,然后动态维护这个数组,找的时候从小到大遍历即可。
#include <cstdio> #include <ctime> #include <cstring> #include <cstdlib> #include <cmath> #include <vector> #include <map> #include <set> #include <stack> #include <queue> #include <string> #include <iostream> #include <algorithm> using namespace std; #define getmid(l,r) ((l) + ((r) - (l)) / 2) #define MP(a,b) make_pair(a,b) #define PB(a) push_back(a) typedef long long ll; typedef pair<int,int> pii; const double eps = 1e-8; const int INF = (1 << 30) - 1; const int MAXN = 100010; int n; int D[MAXN]; pii P[MAXN]; int main(){ scanf("%d",&n); for(int i = 1; i <= n; ++i){ scanf("%d",&P[i].first); } for(int i = 1; i <= n; ++i){ scanf("%d",&P[i].second); D[P[i].second]++; } sort(P + 1,P + n + 1); int sum = 0; int ans = INF; for(int i = n; i >= 1; ){ int cnt = 0; int tmpsum = 0; for(int j = i; j >= 1 && P[j].first == P[i].first; --j,++cnt){ D[P[j].second]--; tmpsum += P[j].second; } int ned = max(0,i - cnt * 2 + 1); int curcnt = 0,cursum = 0; for(int j = 1; j <= 200; ++j){ if(curcnt + D[j] >= ned){ cursum += (ned - curcnt) * j; ans = min(ans,sum + cursum); break; } else{ curcnt += D[j]; cursum += D[j] * j; } } sum += tmpsum; i -= cnt; } printf("%d\n",ans); return 0; }