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/ 希望所写的文章对您有帮助。
  • 相关阅读:
    AOC的服务还不错
    浅谈Java、MySQL的中文排序问题
    祝cnBlogs的Blogger们新年快乐!
    GT 3.9.4以及今天的工作
    堆排序
    桶排序
    常用排序算法稳定性分析
    VS2010远程调试环境配置详解
    基数排序
    如何修改数据库的服务器名称
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12310138.html
Copyright © 2011-2022 走看看