原题:http://codeforces.com/contest/1140/problem/C
题目大意:有n首歌,每首歌有长度和美感值,任意选一些歌(不超过k首),使得它们长度之和与最小美感值的乘积最大
这道题的突破口就是最小美感值这个条件,选定某一首歌作为最小美感的歌,那么剩下能选的歌美感值一定大于这首歌,就是要处理的数据范围缩小了。因此可以先对歌曲按美感值排序,对于每一首歌,找到美感值比它大的若干首歌曲(总数量不能超过k首),求出长度和,再乘以最小美感值(就是这首歌的美感值)。接下来的问题就是怎样快速算出最大长度和。
我们设按美感值从大到小排完序后,歌曲序列为: ,首先,我们总是选择尽可能多的歌曲,比如若i<=k,当i=2时,我们选 , 当i=3时,我们选 ,当k=7时,我们选 ,但是当i>k的时候,我们必须舍弃一些歌曲,具体来说就是舍弃长度最小的歌曲,使得选择的歌曲的总长度仍然为k,这点可以用set做到
note:当时写的时候不知怎么的以为set是从大到小排序,怒交一发WA T_T
完整的代码如下:
#include<bits/stdc++.h>
using namespace std;
const int maxn=3e5+7;
struct Song{
bool operator<(Song&s)
{
return b>s.b;
}
int t;
int b;
}s[maxn];
int k,n;
/*
void show()
{
for(int i=1;i<=n;++i)
{
cout << s[i].t << ' ' << s[i].b << endl;
}
}
*/
int main()
{
#ifdef LOCAL_PC
freopen("E:/1.txt","r",stdin);
#endif // LOCAL
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%d%d",&s[i].t,&s[i].b);
sort(s+1,s+n+1);
multiset<int> lenset;
long long ans=0,sum=0;
for(int i=1;i<=n;++i)
{
lenset.insert(s[i].t);
sum+=s[i].t;
while(lenset.size()>k)
{
auto it=lenset.begin();
sum-=*it;
lenset.erase(it);
}
ans=max(ans, (sum)*s[i].b );
}
cout << ans;
return 0;
}