夺宝奇兵
现场时:一开始我有点纠结,因为不知道是优先当前数量最多的还是优先当前最便宜的。然后我起初的想法就是维护一个当前数量最多并且最便宜的堆,直到当前已拥有的宝物数量大于堆顶的宝物的数量。后来想了想,是不对的,因为我维护的第一关键字是数量最多,所以花费可能并不是最少的,有可能我买另两个个较便宜的宝物从而成为了数量最高,并且此时花费最少。
题解:实际上可以枚举最后成为全场数量最高后的数量,我们设其为 ,我们发现对于宝物数量小于 的都是没有必要买的,因此可以将宝物数量 的最便宜的宝物都买下来,可以用 维护,如果最后数量还达不到 ,我们再从没有被买过的宝物里依次挑选最便宜的直到数量达到 。最后取最小答案即可。
代码
#include<bits/stdc++.h>
#define P pair<int,int>
using namespace std;
typedef long long LL;
const int N = 1001;
multiset<P> g[N], v;
bool vis[N];
int main() {
#ifndef ONLINE_JUDGE
freopen("input.in", "r", stdin);
#endif
int n, m, a, c;
cin >> n >> m;
for (int i = 1; i <= m; ++i) {
cin >> a >> c;
v.insert(P(a,i));
g[c].insert(P(a,i));
}
LL ans = 1e18;
for(int k = 1; k <= m; ++k) {
memset(vis, 0, sizeof vis);
LL ret = 0;
int sum = 0;
for(int i = 1; i <= n; ++i) {
int get = 0;
if(g[i].size() >= k) {
for(auto t : g[i]) {
ret += t.first;
vis[t.second] = 1;
get++;
if(get > g[i].size() - k) break;
}
}
sum += get;
}
for(auto t : v) {
if(sum >= k) break;
if(vis[t.second] == 0) ret += t.first, sum++;
}
ans = min(ans, ret);
}
cout << ans << endl;
return 0;
}