• 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
    ");
                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
    ",ans);
        }
    }
  • 相关阅读:
    基于ARP的网络扫描工具netdiscover
    渗透测试集成环境Faraday
    NBNS扫描工具nbtscan-unixwiz
    分享Kali Linux 2017年第18周镜像文件
    Hat's Fibonacci
    N!
    A + B Problem II(大数加法)
    产生冠军(拓扑排序)
    确定比赛名次
    Legal or Not(模板题)
  • 原文地址:https://www.cnblogs.com/zcb123456789/p/12302062.html
Copyright © 2020-2023  润新知