奪寶奇兵
現場時:一開始我有點糾結,因爲不知道是優先當前數量最多的還是優先當前最便宜的。然後我起初的想法就是維護一個當前數量最多並且最便宜的堆,直到當前已擁有的寶物數量大於堆頂的寶物的數量。後來想了想,是不對的,因爲我維護的第一關鍵字是數量最多,所以花費可能並不是最少的,有可能我買另兩個個較便宜的寶物從而成爲了數量最高,並且此時花費最少。
題解:實際上可以枚舉最後成爲全場數量最高後的數量,我們設其爲,我們發現對於寶物數量小於的都是沒有必要買的,因此可以將寶物數量的最便宜的寶物都買下來,可以用維護,如果最後數量還達不到,我們再從沒有被買過的寶物裏依次挑選最便宜的直到數量達到。最後取最小答案即可。
代碼
#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;
}