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/ 希望所写的文章对您有帮助。
  • 相关阅读:
    Kendo UI开发教程(8): Kendo UI 特效概述
    6.3 计算字符在字符串中出现的次数
    有意思的GacUI
    Qt信号量QSemaphore(在线程里使用,结合生产者消费者的问题)
    Qt 自定义事件详细实例(继承QEvent,然后QCoreApplication::postEvent()、sendEvent())
    为什么选择使用 Dropbox 而不是其他品牌同步工具(不要加上多余的功能,要极致和专注)
    DropBox与Box的区别,包括直接的投资人的评价(本地Sync可能还是挺重要的)
    ASP.NET所谓前台调用后台、后台调用前台想到HTTP——实践篇
    8个免费实用的C++GUI库
    .NET 利用反射将对象数据添加到数据库
  • 原文地址:https://www.cnblogs.com/qieqiemin/p/12310138.html
Copyright © 2011-2022 走看看