D. Fill The Bag

题目链接:http://codeforces.com/contest/1303/problem/D

题意:给你一个大小为m的包,和n个盒子,每个盒子大小为a[i],且a[i]是2的正整数次幂,每个盒子可以拆分成2个大小相等的盒子,问至少经过几次拆分,才能正好装满m的包,如               果不可能则输出-1。

思路:把m化成2进制存入b数组中,由于a[i]是2的正整数次幂,那用c数组统计2的对应次幂分别有多少个,然后遍历m的二进制从低位到高位,如果对应的c数组有,那就c[i]--,否则               的话就看c[1]到c[i-1]是否可以撮成,可以的话就要那些低位撮,不可以的话就找一个高位进行拆分,然后累加拆分次数即可。

#include<stdio.h>
#include<iostream>
#include<string.h>
#include<math.h>
#include<string>
#include<algorithm>
#include<queue>
#include<map>
typedef long long ll;
using namespace std;
ll lo(ll x)
{
    ll v=0;
    while(x)
    {
        v++;
        x/=2;
    }
    return v;
}
ll b[100],c[100];
int main()
{
    int t;
    scanf("%d",&t);
    while(t--)
    {
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        ll m,n;
        scanf("%lld%lld",&m,&n);
        ll sum=0;
        for(int i=1;i<=n;i++)
        {
            ll x;
            scanf("%lld",&x);
            sum+=x;
            c[lo(x)]++;
        }
        if(sum<m)
        {
            printf("-1\n");
            continue;
        }
        int x=0;
        while(m)
        {
            x++;
            b[x]=m%2;
            m/=2;
        }
        ll ans=0;
        for(int i=1;i<=65;i++)
        {
            if(b[i]==0)
                continue;
            if(c[i]>0)
                c[i]--;
            else
            {
                ll y=2,z=-1;
                for(int j=i-1;j>=1;j--)//看是否可以撮成i,
                {
                    if(c[j]>=y)
                    {
                        c[j]-=y;
                        z=j+1;
                        break;
                    }
                    else
                        y-=c[j];
                    y*=2;
                }
                if(z!=-1)//可以则对应的减掉
                {
                    for(int j=z;j<i;j++)
                        c[j]=0;
                }
                else
                {
                    for(int j=i+1;j<=65;j++)//不可以则找高位拆分
                    {
                        if(c[j]>0)
                        {
                            c[j]--;
                            for(int k=j-1;k>=i;k--)
                            {
                                c[k]++;
                                ans++;
                            }
                            break;
                        }
                    }
                }
            }
        }
        printf("%lld\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/zcb123456789/p/12302062.html
今日推荐