Fill The Bag
Problem Description
You have a bag of size n . Also you have m m boxes. The size of i-th box is a i a_i ai , where each a i a_i ai is 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 = 10 n = 10 n=10 and a = [ 1 , 1 , 32 ] a = [1, 1, 32] 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 1 \le t \le 1000 1≤t≤1000) — the number of test cases.
The first line of each test case contains two integers n and m( 1 ≤ n ≤ 1 0 18 , 1 ≤ m ≤ 1 0 5 1 \le n \le 10^{18}, 1 \le m \le 10^5 1≤n≤1018,1≤m≤105) — the size of bag and the number of boxes, respectively.
The second line of each test case contains m m integers a 1 , a 2 , … , a m a_1, a_2, \dots , a_m a1,a2,…,am( 1 ≤ a i ≤ 1 0 9 1 \le a_i \le 10^9 1≤ai≤109) — the sizes of boxes. It is guaranteed that each a i a_i ai is a power of two.
It is also guaranteed that sum of all m m over all test cases does not exceed 1 0 5 10^5 105.
Output
For each test case print one integer — the minimum number of divisions required to fill the bag of size n n n (or − 1 -1 −1 , if it is impossible).
Sample Input
3
10 3
1 32 1
23 4
16 1 4 1
20 5
2 1 16 1 8
Sample Output
2
-1
0
题意
有一个大小为n的包,还有m个物体,每个物体的大小为ai,ai为2的k ( k ≥ 0 ) (k \ge 0) (k≥0)次幂。物体可能太大,可以对物体进行拆分,每次操作,可将大小为ai的物体变为2个大小为ai/2的物体。求是否存在方案正好装满包,如果可以,求最少的操作次数。
题解:
所有的ai都是2的整数次幂,考虑从这方面入手。显然当
a
1
+
a
2
+
a
3
+
.
.
.
+
a
n
<
n
a_1+a_2+a_3+...+a_n < n
a1+a2+a3+...+an<n时无解,否则一定存在方案可以填满。
存在解时考虑最小化操作次数,首先将n分解为
2
p
0
+
2
p
1
+
.
.
.
+
2
p
x
2^{p_0}+2^{p_1}+...+2^{p_x}
2p0+2p1+...+2px的形式。另外统计物体中大小为
2
i
2^i
2i的有多少个。因为ai都是2的整数次幂,所以可以将n看做是x个小包,大小分别为
2
p
0
2^{p_0}
2p0,
2
p
1
2^{p_1}
2p1…
2
p
x
2^{p_x}
2px。
从小到大依次填x个小包,为了最小化操作数,如果一个小包能由许多个小的物体填满,则用多个小物体填满,如果小物体无法填满,再考虑拆分大方块。
判断体积
≤
2
p
i
\le2^{p_i}
≤2pi的未使用物体的和是否大于
2
p
i
2^{p_i}
2pi即可(显然如果和大于等于
2
p
i
2^{p_i}
2pi,是可以找出一种方案正好填满包的)。如果小于,那么则考虑拆分 2^pi次幂需要操作数最小的那个物体即可。
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<ctype.h>
#include<cstring>
#include<map>
#include<queue>
#include<stack>
#include<iterator>
#define dbg(x) cout<<#x<<" = "<<x<<endl;
#define INF 0x3f3f3f3f
#define eps 1e-6
using namespace std;
typedef long long LL;
typedef pair<LL, int> P;
const int maxn = 80;
const int mod = 1000000007;
int b[maxn], c[maxn], d[maxn];
LL B[maxn];
map<LL,int> mp;
void hua(LL n, int a[]);
int main()
{
int t, m, i, j, k;
B[0] = 1, b[0] = 0;
mp[1] = 0;
for(i=1;i<=60;i++)
b[i] = i, B[i] = B[i-1]*2, mp[B[i]] = i;
scanf("%d", &t);
while(t--)
{
int ans = 0, sig = 1;
memset(c, 0, sizeof(c));
memset(d, 0, sizeof(d));
LL n, sum = 0;
scanf("%I64d %d", &n, &m);
for(i=0;i<m;i++){
scanf("%d", &j);
c[mp[(LL)j]]++;
}
hua(n, d);
for(i=0;i<=60;i++)
{
sum += c[i] * B[i];
if(d[i] == 1)
{
if(sum >= B[i]){
sum -= B[i];
}
else
{
sig = 0;
for(j=i+1;j<=60;j++)
if(c[j]>0)
{
c[j]--;
sig = 1;
ans += j-i;
sum += B[j] - B[i];
break;
}
}
}
}
if(sig)printf("%d\n", ans);
else printf("-1\n");
}
return 0;
}
void hua(LL n, int a[])
{
for(int i=60;i>=0;i--)
if(n>=B[i]){
n-=B[i];
a[i]++;
}
}