zoukankan      html  css  js  c++  java
  • [Educational Codeforces Round 82 (Rated for Div. 2)] D. Fill The Bag (二进制拆分,贪心)

    [Educational Codeforces Round 82 (Rated for Div. 2)] D. Fill The Bag (二进制拆分,贪心)

    D. Fill The Bag

    time limit per test

    2 seconds

    memory limit per test

    256 megabytes

    input

    standard input

    output

    standard output

    You have a bag of size nn. Also you have mm boxes. The size of ii-th box is aiai, where each aiai 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=10n=10 and a=[1,1,32]a=[1,1,32] then you have to divide the box of size 3232 into two parts of size 1616, and then divide the box of size 1616. So you can fill the bag with boxes of size 11, 11 and 88.

    Calculate the minimum number of divisions required to fill the bag of size nn.

    Input

    The first line contains one integer tt (1≤t≤10001≤t≤1000) — the number of test cases.

    The first line of each test case contains two integers nn and mm (1≤n≤1018,1≤m≤1051≤n≤1018,1≤m≤105) — the size of bag and the number of boxes, respectively.

    The second line of each test case contains mm integers a1,a2,…,ama1,a2,…,am (1≤ai≤1091≤ai≤109) — the sizes of boxes. It is guaranteed that each aiai is a power of two.

    It is also guaranteed that sum of all mm over all test cases does not exceed 105105.

    Output

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

    Example

    input

    Copy

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

    output

    Copy

    2
    -1
    0
    

    题意:

    t组数据,每一组数据给定一个整数n,以及m个整数(a[i]),保证(a[i])为2的次幂

    代表有一个尺寸为n的箱子,整数a[i]代表一个尺寸为a[i] 的物品,每一个物品可以拆分为2个(frac{a[i]}{2}),由拆分得到的物品可以继续再拆分。

    问最小需要拆分多少次能使箱子装满?如果装不满答案为-1

    思路:

    如果(sum_{i=1}^n a_i < n) 答案为-1,否则可以装满。

    我们考虑从小到大物品尺寸:

    对于物品尺寸为(2^i) 的情况由以下3种:

    1、如果n的二进制表示法中的第i位 等于0,那么我们就用不到尺寸为(2^i)的物品了,我们考虑将其“合并“为(2^{i+1})

    2、如果n的二进制表示法中的第i位 等于1,且我们有至少一个尺寸为(2^i)的物品,然后将其装入盒子,将剩下的(2^i)“合并”为(2^{i+1})

    3、如果n的二进制表示法中的第i位 等于1,我们没有尺寸为(2^i)的物品,然后考虑必须去拆一个更大尺寸(2^x)的物品来装入盒子。答案加上(x-i),再此之后,我们只需要继续该算法从(2^x)开始。

    代码:

    
    /*** TEMPLATE CODE * * STARTS HERE ***/
    ll n;
    int m;
    ll a[400];
    ll b[400];
    int main()
    {
        //freopen("D:\code\text\input.txt","r",stdin);
        //freopen("D:\code\text\output.txt","w",stdout);
        int t;
        t = readint();
        while (t--)
        {
            repd(i, 0, 61)
            {
                a[i] = 0;
                b[i] = 0;
            }
            n = readll();
            m = readint();
            for (int i = 60; i >= 0; --i)
            {
                if (n & (1ll << i))
                {
                    a[i]++;
                }
            }
            repd(i, 1, m)
            {
                ll x = readint();
                for (int j = 30; j >= 0; --j)
                {
                    if (x & (1 << j))
                    {
                        b[j]++;
                    }
                }
            }
            int ans = 0;
            int isok = 1;
            int flag;
            repd(i, 0, 60)
            {
                if (a[i])
                {
                    if (b[i])
                    {
                        b[i]--;
                        b[i + 1] += b[i] / 2;
                    } else
                    {
                        flag = 0;
                        repd(j, i + 1, 60)
                        {
                            if (b[j])
                            {
                                flag = 1;
                                ans += j - i;
                                i = j - 1;
                                b[j]--;
                                break;
                            }
                        }
                        if (!flag)
                        {
                            isok = 0;
                        }
                    }
                } else
                {
                    b[i + 1] += b[i] / 2;
                }
            }
            if (isok)
            {
                printf("%d
    ", ans);
            } else
            {
                printf("-1
    ");
            }
    
        }
    
        return 0;
    }
    
    
    
    
    本博客为本人原创,如需转载,请必须声明博客的源地址。 本人博客地址为:www.cnblogs.com/qieqiemin/ 希望所写的文章对您有帮助。
  • 相关阅读:
    史上最详细 Linux 用户与用户组知识
    MySQL -2- 体系结构--随笔小记
    MySQL -2- 体系结构
    MySQL -1- 简介及安装
    MySQL -0- 课程大纲及课程链接
    探索Windows命令行系列(4):通过命令操作文件和文件夹
    探索Windows命令行系列(3):命令行脚本基础
    探索Windows命令行系列(2):命令行工具入门
    探索Windows命令行系列(1):导航目录
    Oracle 分页方法研究
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12310138.html
Copyright © 2011-2022 走看看