链接:http://codeforces.com/contest/1140/problem/C
题意:
给出n个元素, 元素有两个值: 长度l和价值v. 要找到k个以内元素构成的集合, 使得集合中 长度和 * 最小价值 最大.
思路:
如果以某个元素的v作为最小价值, 那么其余只需要取 价值大于v且长度和最大 的k-1个元素即可.
那么将元素按v从大到小排序, 遍历全部元素. 每到第i个元素, 考虑前i个元素能得到的最大长度和, 答案用长度和*当前元素的价值更新.
最大长度和的写法: 因为已经对元素按价值排序, 而且答案只与最小价值有关, 所以对于第i个元素, 前i-1个元素的价值是没有意义的. 因此, 可以用优先队列维护构成当前最优情况的k个长度值, 每次更新i时, 若队列中元素个数>k, 只需要将最小的长度pop即可.
p.s.如果新入的元素直接被排除(长度在优先队列中最小), 这次的更新没有意义, 并且不会影响结果(因为这相当于上一个放入的i所构成的情况, 而且这次错误更新ans一定比上一次的ans更差).
代码:
#include<bits/stdc++.h>
#define fuck(x) std::cout<<"["<<#x<<"->"<<x<<"]"<<endl;
using namespace std;
typedef long long ll;
const int M=3e5+5;
const int inf=1e9+5;
struct node {
ll l,v;
} a[M];
bool cmp(node a,node b) {
return a.v>b.v;
}
int main() {
int n,k;
scanf("%d%d",&n,&k);
for(int i=0; i<n; i++) {
scanf("%I64d%I64d",&a[i].l,&a[i].v);
}
sort(a,a+n,cmp);
priority_queue<ll,vector<ll>, greater<ll> >q;
ll nowlen=0;
ll ans=0;
for(int i=0; i<n; i++) { //dang guole i hou,zhiqiande v jiu meiyou yiyi le
//ans zhiyu zuixiaode v youguan
//suoyi keyi zhi baocun meige yuansu de l
q.push(a[i].l);
nowlen+=a[i].l;
if(q.size()>k) {
nowlen-=q.top();
q.pop();
}
ans=max(ans,nowlen*a[i].v);//if gang jinlai de yuansu qiahao bei zhijie pop
//bingbu yingxiang ans
//caz zhege qingkuang xiangdangyu qianyige i de ans
}
printf("%I64d\n",ans);
return 0;
}