[Educational Codeforces Round 62 (Rated for Div. 2) C. Playlist] 个人题解

原题:http://codeforces.com/contest/1140/problem/C

题目大意:有n首歌,每首歌有长度和美感值,任意选一些歌(不超过k首),使得它们长度之和与最小美感值的乘积最大

这道题的突破口就是最小美感值这个条件,选定某一首歌作为最小美感的歌,那么剩下能选的歌美感值一定大于这首歌,就是要处理的数据范围缩小了。因此可以先对歌曲按美感值排序,对于每一首歌,找到美感值比它大的若干首歌曲(总数量不能超过k首),求出长度和,再乘以最小美感值(就是这首歌的美感值)。接下来的问题就是怎样快速算出最大长度和。

 

我们设按美感值从大到小排完序后,歌曲序列为:   $s_1,s_2,s_3,...,s_n$  ,首先,我们总是选择尽可能多的歌曲,比如若i<=k,当i=2时,我们选 $s_1,s_2$ , 当i=3时,我们选 $s_1,s_2,s_3$ ,当k=7时,我们选 $s_1,s_2,s_3,...,s_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;
}

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页