CCPC-Wannafly Winter Camp Day1 (Div2, onsite) J 奪寶奇兵(貪心)

奪寶奇兵

現場時:一開始我有點糾結,因爲不知道是優先當前數量最多的還是優先當前最便宜的。然後我起初的想法就是維護一個當前數量最多並且最便宜的堆,直到當前已擁有的寶物數量大於堆頂的寶物的數量。後來想了想,是不對的,因爲我維護的第一關鍵字是數量最多,所以花費可能並不是最少的,有可能我買另兩個個較便宜的寶物從而成爲了數量最高,並且此時花費最少。

題解:實際上可以枚舉最後成爲全場數量最高後的數量,我們設其爲kk,我們發現對於寶物數量小於kk的都是沒有必要買的,因此可以將寶物數量k\geq k的最便宜的寶物都買下來,可以用multisetmultiset維護,如果最後數量還達不到kk,我們再從沒有被買過的寶物裏依次挑選最便宜的直到數量達到kk。最後取最小答案即可。

代碼

#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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章