CodeForces - 1303 D Fill The Bag 二进制

一、内容

You have a bag of size n. Also you have m boxes. The size of i-th box is ai, where each aiis an integer non-negative power of two.You can divide boxes into two parts of equal size. Your goal is to fill the bag completely.For example, if n=10and a=[1,1,32] then you have to divide the box of size 32 into two parts of size 16, and then divide the box of size 16. So you can fill the bag with boxes of size 1, 1 and 8.Calculate the minimum number of divisions required to fill the bag of size n

Input

The first line contains one integer t(1≤t≤1000) — the number of test cases.The first line of each test case contains two integers nand m (1≤n≤1018,1≤m≤105) — the size of bag and the number of boxes, respectively.The second line of each test cascontainsmintegersa1,a2,…,am (1≤ai≤109) — the sizes of boxes. It is guaranteed that each aiis a power of two.It is also guaranteed that sum of allmover all test cases does not exceed 105

Output

For each test case print one integer — the minimum number of divisions required to fill the bag of size n(or −1 , if it is impossible).

Input

3
10 3
1 32 1
23 4
16 1 4 1
20 5
2 1 16 1 8

Output

2
-1
0

二、思路

  • 首先如果所有的数的和不大于n的话,那么必然是-1
  • 如果大于的话那么就从前往后的枚举n的二进制位。 如果这个二进制为上为1,那么判断下这个2进制位上是否有数,如果有数的话就可以消去。 如果没有数的话,只能从前面的二进制位进行划分。
  • 最后将当前位的二进制数进行合并到前一位。

三、代码

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
int t, m;
ll n, a, ans[65], cnt[65];
void solve() {
	memset(ans, 0, sizeof(ans));
	memset(cnt, 0, sizeof(cnt));
	scanf("%lld%d", &n, &m); ll sum = 0;
	for (int i = 1; i <= m; i++) {
		scanf("%lld", &a); sum += a; 
		for (int i = 0; i <= 30; i++) if (a & (1ll << i)) cnt[i]++;
	}
	if (sum < n) {printf("-1\n"); return ;}
	for (int i = 0; i <= 60; i++) if (n & (1ll << i)) ans[i]++;
	int ci = 0;
	for (int i = 0; i <= 60; i++) {
		if (ans[i]) {
			//寻找是否能够凑 不能够只能划分
			if (!cnt[i]) {
				int t = i + 1; while (!cnt[t]) t++;
				for (int j = t; j > i; j--) {
					cnt[j]--; cnt[j - 1] += 2; ci++;
				}
			} 
			cnt[i]--; ans[i] = 0;
		} 
		//合并
		cnt[i + 1] += cnt[i] / 2;
	}
	printf("%d\n", ci);
}
int main () {
	scanf("%d", &t);
	while (t--) solve();
	return 0;
} 
发布了446 篇原创文章 · 获赞 455 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/qq_41280600/article/details/104411518