這道題是在與學弟吃飯的路上聽學弟講的,感覺挺有意思的,需要不少的思維(可能我長時間沒有刷題了,有點笨了~) 特此記錄一下: Problem: 有n個(x,y)元組,求從中取出k個元組,使得這k個元組的x之和乘以其中最小的y值的值最大 ( sum(x)*min(y) in k個元組 ) Solutio ...
這道題是在與學弟吃飯的路上聽學弟講的,感覺挺有意思的,需要不少的思維(可能我長時間沒有刷題了,有點笨了~)
特此記錄一下:
Problem:
有n個(x,y)元組,求從中取出k個元組,使得這k個元組的x之和乘以其中最小的y值的值最大 ( sum(x)*min(y) in k個元組 )
Solution:
將n個元組按照y值從小到大排序,然後從小到大枚舉每個y值,以當前的y值為選取的k個元組中的最小值,那麼k個元組位於當前元組之後(一定包含當前元組)。也就是說,有k-1個元組還未確定,需要從當前元組之後選 取 k-1個最大的x值對應的元組。那麼問題簡化為從當前元組後取k-1個最大的數。計算出sum_i(x)*min_i(y),i為當前元組的index, 取最大值就是正確的答案了。
為了提高枚舉轉移的速度,我們用兩個集合來維護i+1-n的元組中最大的k-1個x之和。set2中存儲最大的k-1個x,set1中存儲剩餘的x(index=i+1~n的元組),這樣轉移的時候需要判斷元組[i+1].x是否在set1中,在則直接剔 除;否則一定在set2中,則需要剔除,並從set1中取出最大的x,當然取出後set1需要剔除這個x。
代碼如下:
#include <iostream> #include <algorithm> #include <string> #include <set> using namespace std; //Problem: 有n個(x,y)元組,求從中取出k個元組,使得這k個元組的x之和乘以其中最小的y值的值最大 ( sum(x)*min(y) in k個元組 ) //Solution: 將n個元組按照y值從小到大排序,然後從小到大枚舉每個y值,以當前的y值為選取的k個元組中的最小值,那麼k個元組位於當前元組之後(一定包含當前元組)。也就是說 // 有k-1個元組還未確定,需要從當前元組之後選取k-1個最大的x值對應的元組。那麼問題簡化為從當前元組後取k-1個最大的數。計算出sum_i(x)*min_i(y),i為當前元組的 // index, 取最大值就是正確的答案了。 // 為了提高枚舉轉移的速度,我們用兩個集合來維護i+1-n的元組中最大的k-1個x之和。set2中存儲最大的k-1個x,set1中存儲剩餘的x(index=i+1~n的元組),這樣轉移的 // 時候需要判斷元組[i+1].x是否在set1中,在則直接剔除;否則一定在set2中,則需要剔除,並從set1中取出最大的x,當然取出後set1需要剔除這個x。 const int N = 1e5 + 5; typedef pair<int, int> Tuple; bool cmp(const Tuple a, const Tuple b) { return a.second < b.second; } multiset<int> s1, s2; multiset<int>::iterator it; multiset<int>::reverse_iterator rit; int main() { int n, k; cin >> n >> k; Tuple data[N]; for (int i = 0; i < n; i++) { cin >> data[i].first >> data[i].second; } sort(data, data + n, cmp); for (int i = 1; i < n; i++) { s1.insert(data[i].first); } int ans = 0; int sum = 0; for (int i = 1; i < k; i++) { int max_val = *s1.rbegin(); s1.erase(s1.find(max_val)); s2.insert(max_val); sum += max_val; } for (int i = 0; i +k-1< n; i++) { ans = max(ans, data[i].second*(sum+data[i].first)); if (n - i == k) break; if (s1.count(data[i+1].first) >0) { it = s1.find(data[i+1].first); s1.erase(it); } else { it = s2.find(data[i+1].first); sum -= *it; s2.erase(it); rit = s1.rbegin(); sum += *rit; s2.insert(*rit); s1.erase(s1.find(*rit)); } } std::cout << "Answer = " << ans << endl; return 0; } /* 5 2 2 3 4 1 5 7 1 3 6 3 */