Codeforces 1140C 题解

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

题意简述

给定 n n n个歌曲,每个歌曲有长度值len和美丽值bea。选出最多(珂以<=) k 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表示这些歌曲(同代码中)。然后,按照这类问题的套路,我们需要先枚举一个 t [ i ] . b e a t[i].bea t[i].bea,并且强制它是最小值。
如何强制呢?
我们按 b e a bea bea降序把 t t t排一下序,然后由于 b e a bea bea是降序的,我们强制 t [ i ] . b e a t[i].bea t[i].bea是最小,相当于我们必须选 t [ i ] . b e a t[i].bea t[i].bea,并且 t [ i 后面 ] . b e a t[i\text{后面}].bea t[i后面].bea都不能选。这样就简单很多了:我们枚举 t [ i ] . b e a t[i].bea t[i].bea的时候,就相当于只考虑 1 1 1~ i i i
然后我们过一遍,如果没选满 k k k个,则 i i i一定要选。如果选满了 k k k个,那我们一定是找一个 l e n len 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值