Codeforces 1140C 题解

版权声明:博主是个蒟蒻,希望大家支持,如果要转发就转发吧,把我链接挂上即可。 https://blog.csdn.net/LightningUZ/article/details/89036190

这个题是一次比赛的题,是我第一次背着父母熬夜打CF。当时我开始做这个题的时候是晚上12:00,我爸突然进来告诉我叫我早点睡(没骂我已经很好了),当时心态直接崩了,明明会做,却挂了。(我现在写这篇博客是强忍着心理阴影在讲。。。)

题意简述

给定 n n 个歌曲,每个歌曲有长度值len和美丽值bea。选出最多(珂以<=) k k 个,使得这些歌曲中bea的最小值 × \times len的和 最大。

数据

输入:
4 3
4 7
15 1
3 6
6 8
输出:
78

输入:
5 3
12 31
112 4
100 100
13 55
55 50
输出:
10000

思路

暴力枚举肯定超时。
线段树?好像也不能做。
。。。?
。。。?
。。。?
。。。?
(吓得我蒙成一个蒟阵)
我们用 t t 表示这些歌曲(同代码中)。然后,按照这类问题的套路,我们需要先枚举一个 t [ i ] . b e a t[i].bea ,并且强制它是最小值。
如何强制呢?
我们按 b e a bea 降序把 t t 排一下序,然后由于 b e a bea 是降序的,我们强制 t [ i ] . b e a t[i].bea 是最小,相当于我们必须选 t [ i ] . b e a t[i].bea ,并且 t [ i 后面 ] . b e a t[i\text{后面}].bea 都不能选。这样就简单很多了:我们枚举 t [ i ] . b e a t[i].bea 的时候,就相当于只考虑 1 1 ~ i i
然后我们过一遍,如果没选满 k k 个,则 i i 一定要选。如果选满了 k k 个,那我们一定是找一个 l e n len 最小的,踢掉,最划算。找最小的过程就用优先队列维护。
最后输出找到的最大即可。
代码:

#include<bits/stdc++.h>
#define int long long
#define N 1001000
using namespace std;
struct song//歌曲
{
    int len,bea;
    const bool operator<(const song CompWith) const
    {
        return bea>CompWith.bea;//按bea从大到小
    }
}t[N];//和思路部分的名字同步
int n,k;

void Input()
{
    scanf("%I64d%I64d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%I64d%I64d",&t[i].len,&t[i].bea);
    }
}

priority_queue<int,vector<int>,greater<int> >Q;
//维护最小的len
//一定要写greater<int>,这样每次取Top就变成最小了
void Solve()
{
    sort(t+1,t+n+1);//先排序
    int ans=0,sum=0;//ans的初始值珂以是0,珂以是-1,也可以是-1000000000
    //但sum不一样,是记录和的,一开始一定要是0
    for(int i=1;i<=n;i++)
    {
        if (Q.size()<k)//没选满k个
        {
            Q.push(t[i].len);//选上
            sum+=t[i].len;
            ans=max(ans,sum*t[i].bea);//更新答案
        }
        else
        {
            sum-=Q.top();Q.pop();//踢掉那个最小的
            Q.push(t[i].len);//选上新的
            sum+=t[i].len;
            ans=max(ans,sum*t[i].bea);//更新答案
        }
    }
    printf("%I64d\n",ans);
}

main()
{
    Input();
    Solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/LightningUZ/article/details/89036190