codeforces1303D Fill The Bag 二进制应用+贪心

网址:https://codeforces.com/contest/1303/problem/D

题意:

给出空间为$n$的容器和$m$个盒子。这些盒子的大小都是$2^k$的正整数,且可以减半,问使得容器刚好被盒子装满的最小减半次数是多少,如果不可能刚好装满,输出$-1$。

题解:

统计$2^k$大小的盒子有多少个,然后从低位到高位贪心,因为高位的一定需要减半才能到低位,所以就会增加减半次数,而低位变成高位却无影响。对于某一位$i$,如果它是$1$,那么对于这一位,如果已经没有了大小是$2^i$的盒子,则需要从$i+1$位的减半一次,$i+1$位上的盒子数是$-1$也没有关系,因为它会从$(i+1)+1$位拿过来,类似于减法退位。如果有剩下的,就直接合并到$i+1$位,最后输出减半次数就是答案。

AC代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int cnt[65];
int solve()
{
	memset(cnt, 0, sizeof(cnt));
	ll n, sum = 0;
	int m, a;
	scanf("%lld%d", &n, &m);
	for (int i = 1; i <= m; ++i)
	{
		scanf("%d", &a);
		sum += a;
		int tmp = 0;
		while (a > 1)
			++tmp, a >>= 1;
		++cnt[tmp];
	}
	if (sum < n)
		return printf("-1
"), 0;
	int ans = 0;
	for (int i = 0; i <= 63; ++i)
	{
		int x = (n >> i) & 1;
		cnt[i] -= x;
		if (cnt[i] >= 2)
			cnt[i + 1] += cnt[i] / 2, cnt[i] -= (cnt[i] / 2) * 2;
		if (cnt[i] < 0)
			--cnt[i + 1], ++ans;
	}
	return printf("%d
", ans), 0;
}
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
		solve();
	return 0;
}
原文地址:https://www.cnblogs.com/Aya-Uchida/p/12319619.html