牛客挑战赛45_A:除2!(优先队列)

链接https://ac.nowcoder.com/acm/contest/8563/A

题目
给一个数组,一共有 n个数。
你能进行最多 k次操作。每次操作可以进行以下步骤:
选择数组中任意的一个偶数 a_i,将其变成 a_i/2 。
现在你进行不超过k次操作后,让数组中所有数之和尽可能小。请输出这个最小的和。

思路
真的没想到自己没爆0,一开始只是抱着长见识的心情参加的,想不到出题人如此仁慈,跪谢大佬!

题意非常清楚,给你n个数字,你可以对其中任意一个偶数进行取半操作。
在不超过k次操作的情况下,问你能得到的所有数的最小和。
首先我们先考虑,如果一个偶数没有,我们就直接输出序列和就ok了。而且我们只需要对偶数操作,奇数就不需要存储起来。
所以对于输入的数字,奇数就给它求和,偶数存储起来

对于偶数的处理,我相信基本上大家应该都能想到,我们每次都去对序列中最大的偶数取半就可以了。
(应该不会有想不出来的吧,不会吧,不会吧~)
在这里插入图片描述
那这样就产生了一个难题:怎么在不超时的前提下去维持偶数序列的有序呢?
我们肯定不能每次都排个序然后去找最大值,会T掉的。(我写了,一发T了,有什么好说的?)

这时我的脑海里出现了一个东西:优先队列(priority_queue),这不正是我朝思暮想的东西吗?
所以存储问题就解决了,剩下的就easy了。

还有一点就是偶数除2还可能会变成奇数,这个时候我们就不用处理它了,把他移除队列就好。

剩下的看代码,伊丽莎白!

在这里插入图片描述
代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;        //int会爆掉,开long long
int main()
{
    ll n,m,k,x;
    ll sum=0;
    priority_queue<ll>a;     //优先队列
    scanf("%lld%lld",&n,&k);
    for(ll i=0; i<n; i++)
    {
        scanf("%lld",&x);
        if(x%2)              //如果是奇数,直接求和
            sum+=x;
        else                 //如果是偶数,扔进优先队列里
            a.push(x);
    }
    if(a.empty())            //队列为空,说明全是奇数
        printf("%lld\n",sum);
    else
    {
        ll m;
        while(k--&&!a.empty())  //既要保证还有操作次数,还要保证还有偶数可以让我们操作
        {
            m=a.top();          //这里定义的优先队列默认是大顶堆(从大到小)
            a.pop();            //把最大的踢出队伍
            m/=2;
            if(m%2)             //如果取半之后是奇数,就算入sum里,不再放回队伍
                sum+=m;
            else
                a.push(m);      //还是偶数就再送回队伍
        }
        while(!a.empty())       //看看还有没有偶数
        {
            m=a.top();
            a.pop();
            sum+=m;
        }
        printf("%lld\n",sum);
    }
}

开心开心~~
蓝桥国赛冲冲冲!!!

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值