• [Bzoj 1192][HNOI2006]鬼谷子的钱袋(二进制优化多重背包)


    人生第一篇bzoj题解有点激动 

    首先介绍一下题目:

            看它题目那么长,其实意思就是给定一个数a,求将其拆分成n个数,通过这n个数可以表示出1~a中所有数的方案中,求最小的n。

           您看懂了嘛?不懂咱来举个栗子:

           3可以变为(1,2)两个数(废话,我当然知道),使1,2可以表示出1,2,3这些数字。看到这道题就想到了不久前看到的二进制优化多重背包。简直一模一样。

           我们想我们对于一个数P。我们可以将其分成两部分(1~P/2)与(P/2+1,P),我们思考:假设我们已经知道(1~P/2)至少需要m个数,那么我们完全可以在左区间的基础上添加一个P/2这个数,使这m+1个数可以表示(1~P)的所有数,因为(1+P/2~P/2+P/2)=(P/2+1~P)。

           我们其实又可以通过手+草稿纸发现关于一个P的最小值n是有(1~P)的左半边区间(1~P/2)的最小值+1有关,而(1~P/2)的最小值又与它本身的左半边区间的值有关,所以事实上这是一个可以递推的过程。

           然后我们归纳总结一下——P与P/2有关,P/2又与P/4有关,很容易联想到二进制。我们只要手算过后稍一扩展我们便会发现——关于一个数P,我们使一个数s满足2s -1<P,注意严格小于P,即s为log2(P),那么这一个数P可以被1,2,4.......2s-1,P-2 +1 分解。

          那么其实我们很快就可以知道一个数P所对应最小n了,其实就是log2(P)+1.那么这道题一下变得简单了起来,贴代码

    #include<iostream>
    #include<cmath>
    #include<cstdio> 
    using namespace std;
    int main()
    {
        long long a;
        scanf("%lld",&a);
        printf("%lld",(long long )log2(a)+1);
    }
    鬼谷子的钱袋

         其实这道题在luogu上有加强版本https://www.luogu.org/problem/P2320,其要求输出每个钱袋的数量,这道题也很简单,我们通过上面的推理先求出S,再以此求出1~2s-1 和P-2s+1再排序输出即可(据说原本只有算n,luogu加上了这道题,然而数据貌似有锅

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    using namespace std;
    long long p,s,k;
    int main()
    {
        scanf("%lld",&p);
        printf("%lld
    ",(long long)log2(p)+1);
        s=log2(p);
        k=p-(1<<s)+1;
            for(long long i=0;i<=s-1;i++)
            {
                if(1<<i>k&&k!=0)
                {
                    printf("%lld ",k);
                    k=0;
                }
                printf("%lld ",1<<i);
            }
            if(k!=0)
            printf("%lld ",k);
        return 0;
     } 
    鬼谷子的钱袋(加强版

    接下来简单描述一下标题所写的二进制优化多重背包

    一般来说我们的多重背包的思路是枚举取n个同种物品,转化为01背包

    那这样的时间复杂度 O(NV*∑(V/W[i])).(V为体积,W[i]为每件的费用)

    但假如我们将每件物品都像鬼谷子的钱袋一样二进制拆分,那每一个物品都会被拆成log2(W[i])+1个物品

    那这样再做01背包所要的时间复杂度为 O(V*log(W[i])+V)(PS:这个时间复杂度有可能写错了,但是应该差不多)

    关于二进制优化多重背包以后我会再写一篇博客来讲,这篇主要的是题解hhh

    您理解了嘛,慢走。

    不理解的可以加qq2733524923我们一起探讨哦

  • 相关阅读:
    20200813质因数分解 --已知正整数n是两个不同的质数的乘积,试求出较大的那个质数 (奥赛一本通 P71 8)
    20200807求梯形面积,要求输入浮点数,输出精度为2位
    c++语言printf()输出格式大全 scanf()输入格式大全
    20200803给出一 名学生的语文和数学成绩,判断他是否恰好有一门课不及格(<60分),如果是输出1;否则输出0(奥赛一本通 p32 10)
    20200803-判断一个数能否同时被3,5,7整除(奥赛一本通 p32 9)
    20200802--利用公式 e=1+1/1!+1/2!+...+1/n!,求e的值, 要求保留小数点后10位(奥赛一本通 p67 2)
    20200802 给定正整数n,求不大于n的正整数的阶乘的和(即求1!+2!+...+n!),输出阶乘的和 (奥赛一本通p67 1题)
    线程
    mysql逻辑架构
    《python网络数据采集》笔记2
  • 原文地址:https://www.cnblogs.com/dixiao/p/11415941.html
Copyright © 2020-2023  润新知