除2! \operatorname{除2!} 除2!
题目链接: nowcoder 213140 \operatorname{nowcoder\ 213140} nowcoder 213140
到牛客看:
题目
给一个数组,一共有
n
n
n 个数。
你能进行最多
k
k
k 次操作。每次操作可以进行以下步骤:
选择数组中的一个偶数
a
i
a_i
ai,将其变成
a
i
/
2
a_i/2
ai/2。
现在你进行不超过
k
k
k 次操作后,让数组中所有数之和尽可能小。请输出这个最小的和。
输入
第一行输入两个正整数
n
n
n 和
k
k
k,用空格隔开
第二行输入
n
n
n 个正整数
a
i
a_i
ai
输出
一个正整数,代表和的最小值。
样例输入
5 3
2 4 8 10 11
样例输出
24
样例解释
对 8 8 8 操作 2 2 2 次,对 10 10 10 操作 1 1 1 次,最后的数组是 2 4 2 5 11 2\ 4\ 2\ 5\ 11 2 4 2 5 11。可以证明这样的操作是最优的。
数据范围
1
≤
n
≤
100000
,
1
≤
k
≤
1
0
9
1 ≤ n≤100000,1≤k≤10^9
1≤n≤100000,1≤k≤109
1
≤
a
i
≤
1
0
9
1≤a_i≤10^9
1≤ai≤109
思路
一道小贪心。
我们很明显可以看出,我们要进行操作是总和变得更小,肯定每一次就是贪心选择最大的偶数进行操作。
(因为这样总和减去的值就会大)
我就直接弄个了堆,把所有偶数丢进去,奇数就直接算进答案里面。
然后每次把最大的拿出来
/
2
/2
/2,如果变成了奇数,就直接算进答案里面,否则就重新把除了之后的数塞进去。
然后最后把堆里的数加进答案,就可以了。
然后如果堆空了(就是所有数都变成了奇数),那就直接退出,不用枚举 k k k 次那么多。
代码
#include<queue>
#include<cstdio>
#include<algorithm>
using namespace std;
priority_queue <int> a;
int n, k, x;
long long ans;
int main() {
scanf("%d %d", &n, &k);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
if (x & 1) ans += (long long)x;
else a.push(x);
}
while (k && !a.empty()) {
x = a.top();
a.pop();
x /= 2;
if (x & 1) ans += (long long)x;
else a.push(x);
k--;
}
while (!a.empty()) ans += (long long)a.top(), a.pop();
printf("%lld", ans);
return 0;
}