D. Fill The Bag

D. Fill The Bag
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
You have a bag of size n. Also you have m boxes. The size of i-th box is ai, where each 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 and 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 n and m (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 integers a1,a2,…,am (1≤ai≤109) — the sizes of boxes. It is guaranteed that each ai is a power of two.

It is also guaranteed that sum of all m over 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).

Example
inputCopy
3
10 3
1 32 1
23 4
16 1 4 1
20 5
2 1 16 1 8
outputCopy
2
-1
0

题意:
给你一个序列,问你能不能组合出n,你可以把其中一个数变成他的一半,问你最少的操作次数。

思路:
首先输入的时候处理一下x,累加后看和s是否大于m,如果小于输出-1。
边输入边预处理,cnt[]为原序列中的第i位是否有数。
把m拆成二进制,从低位到高位枚举,注意如果把16拆成4的话,cnt[3 (2^3=8)]也要更新,就是更新拆分的路径。

代码:

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define ll long long
//#define ll unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-6
#define pi acos(-1)
#define mea (memset(a,0,sizeof(a)))
#define myit set<ll>::iterator
#define mysets multiset<ll>
#define myits multiset<ll>::iterator
#define v30 (1<<30)-1
#define all(x) (x).begin(),(x).end()
#define maxs *s.rbegin()
#define fi first
#define se second
#define lowbit(x) (x&(-x))
#define mid ((a[k].r+a[k].l)>>1)
#define lson k<<1,l,mid
#define rson k<<1|1,mid+1,r
#define kl k<<1
#define kr k<<1|1
using namespace std;
inline ll read(){
   ll s=0,w=1;
   char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
   return s*w;
}
void put1(){ puts("YES") ;}
void put2(){ puts("NO") ;}
void put3(){ puts("-1"); }
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b);}
using namespace std;
 
const int manx=1e5+10;
 
ll cnt[manx];
int main()
{
	ll p=read();
	while(p--){
        ll m=read(),n=read(),s=0,ans=0;
        for(int i=0;i<=30;i++) cnt[i]=0;
        for(int i=1;i<=n;i++){
            ll x=read(),tot=0;
            s+=x;
            while(x>1) tot++,x>>=1;
            cnt[tot]++;
        }
        if(s<m){
            put3();
            continue;
        }
        s=0;
        for(int i=0;i<=62;i++){
            if( (1<<i) & m )  /*cout<<m<<" "<<(1<<i)<<endl,*/s--;
            if(s<0){
                int k=i;
                while(!cnt[k]) cnt[k++]=1;
                cnt[k]--;
             //   cout<<k<<" "<<i<<endl;
                ans+=k-i;
                s=0;
            }
            s+=cnt[i];
            s>>=1;
        }
        cout<<ans<<endl;
	}
	return 0;
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值