SRM 415 DIV1 Medium CollectingPostmarks
http://community.topcoder.com/stat?c=problem_statement&pm=9958&rd=13506
回答
他の人の回答を見た。
まず、持ってるものは売ってから買っても同じなので、まず全部売ってから考える。
ナップザック問題にできて、値の範囲的にDPはできないので指数時間がかかる。
半分を全列挙してから、ソートして、
もう半分を全列挙し、それと最初の半分との和で二分探索をし、その価値である最小のpriceを求める。これは最初にソートした後に次のようにすればいいらしい。
sort(q, q+qn); //valueに基づき、最初の半分の全(value, price)をソートする for(int i = qn-1; i > 0; i --) q[i-1].second = min(q[i-1].second, q[i].second); //q' i = min (q i) (q' (i+1)) //valueでソートされていることに注意すると、 //つまりvalueが小さいのにもかかわらずpriceが大きいものは、 //大きい方のvalueのやつでできるよね、っていう感じ
それらの最小値を取る。
コメント
こういう解き方は知らなかった。頻出で、知らなかったらわからないと思うので、しっかり覚えておきたい
コード
#include <string> #include <vector> #include <algorithm> #include <set> #include <map> #include <queue> #include <iostream> #include <sstream> #include <numeric> #include <cstdio> #include <cmath> #include <ctime> #include <cstring> #define rep(i,n) for(int (i)=0;(i)<(int)(n);(i)++) #define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);(i)++) #define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);(i)++) #define aut(r,v) typeof(v) r = (v) #define each(it,o) for(aut(it,o.begin()); it != (o).end(); it ++) #define all(o) (o).begin(), (o).end() #define pb(x) push_back(x) #define mp(x,y) make_pair((x),(y)) #define mset(m,v) memset(m,v,sizeof(m)) #define INF 0x7f1f1f1f using namespace std; typedef long long ll; typedef vector<int> vi; typedef pair<int,int> pii; pii q[1<<16]; struct CollectingPostmarks { int amountOfMoney(vector <int> prices, vector <int> have, vector <int> values, int K) { int n = prices.size(); int hav = 0; each(i, have) hav += prices[*i]; int m = n/2; int qn = 0; rep(i, 1<<m) { int w = 0, p = 0; rep(j, m) if(i & (1<<j)) p += prices[j], w += values[j]; q[qn++] = mp(w, p); } sort(q, q+qn); for(int i = qn-1; i > 0; i --) q[i-1].second = min(q[i-1].second, q[i].second); int r = INF; rep(i, 1<<(n-m)) { int w = 0, p = 0; rep(j, (n-m)) if(i & (1<<j)) p += prices[m+j], w += values[m+j]; if(q[qn-1].first+w < K) continue; //二分探索 int l = -1, u = qn; while(u - l > 1) { int m = (l + u) / 2; if(q[m].first + w >= K) u = m; else l = m; } r = min(r, p + q[u].second); } return r == INF ? -1 : max(0, r - hav); //見た } };