zoukankan      html  css  js  c++  java
  • ZCMU 1894: Power Eggs

    http://acm.zcmu.edu.cn/JudgeOnline/problem.php?id=1894

    题意:

    有M个鹰蛋,N层楼,鹰蛋的硬度是E,也就是说在1~E层楼扔下去不会碎,E+1层楼扔下去会碎。
    给定M,N,问最坏情况下至少几次能得到E的具体的值。(E可能为0)
    ①n<=100。
    ②n<=1000。
    ③n<=100000。
    ④n<=1000000。
    ⑤n<=1000000000。
     
    推荐学习资料: 朱晨光IOI2004集训队论文 从《鹰蛋》一题浅析对动态规划算法的优化
     

    算法一: O(n^3)

    dp[i][j] 表示用i个蛋在j层楼上确定E,最坏情况下的最少次数
    枚举在第w层扔下1个蛋,要么碎,要么不碎
    碎:用剩下的i-1个蛋在下面的w-1层里确定E
    不碎:剩下的i个蛋在 w+1~n 层里确定E,这相当于在 下面的n-w 层确定E
    所以dp[i][j]=min{ max(dp[i-1][w-1],dp[i][j-w]) } +1
    事件复杂度为 O(n^2 * m),m认为与n同阶
     

    算法二:O(n^2 * logn)

    根据判定树的理论,长为n的有序线性表,最坏查找需要次数为logn [上取整]
    所以当鹰蛋的个数超过 log(n+1) [上取整] 时,直接输出log(n+1) [上取整]
     

    算法三:O(n*logn*logn)

    比较显然的结论:dp[i][j]>=dp[i][j-1]
    (严谨的证明去看论文)
    dp[i][j]=min{ max(dp[i-1][w-1],dp[i][j-w]) } +1
    dp[i-1][w-1] 随w的增大单调不减
    dp[i][j-w] 随w的增大单调不增
    对于每一个w,对应的这两条线谁在上面就取谁
    所以最终更新 dp[i][j]的w是这两条线的交点
    可以二分找这个w
     

    算法四:O(n*logn)

    dp[i][j]=min{ max(dp[i-1][w-1],dp[i][j-w]) } +1
    对于任意的w,满足 dp[i][j]<= max(dp[i-1][w-1],dp[i][j-w])  +1
    令w=1,那么dp[i][j]<= max(dp[i-1][0],dp[i][j-1])  +1
    所以dp[i][j]<=dp[i][j-1]+1
    所以 dp[i][j-1]<=dp[i][j]<=dp[i][j-1]+1
     
    所以若存在一个w,能够使得dp[i][j]=dp[i][j-1],则dp[i][j]=dp[i][j-1]
    若对于所有的w,都不能使得dp[i][j]=dp[i][j-1],则dp[i][j]=dp[i][j-1]+1
     
    令p满足 dp[i][p]=dp[i][j-1]-1,dp[i][p+1]=dp[i][j-1]
    那么dp[i][p]=dp[i][j-1]-1
    dp[i][p+1]=dp[i][p+2]=……=dp[i][j-1]
     
    计算dp[i][j]时,令j-w=p,则w=j-p
    则 dp[i][j]=min{ max(dp[i-1][j-p-1],dp[i][p])  }
    可以证明
    当 dp[i-1][j-p-1]<=dp[i][p] 时,dp[i][j]=dp[i-1][j]
    当 dp[i-1][j-p-1]>dp[i][p] 时,dp[i][j]=dp[i-1][j]+1
    具体证明去看论文
     

    算法五:

    dp[i][j] 表示 用i个蛋,扔j次最坏情况下最大能确定的楼层数

    扔一次碎了,那么剩下j-1次,剩下i-1个蛋

    我们也希望用剩下的次数和剩下的蛋在下面能确定的楼层数最大,所以是dp[i-1][j-1]

     扔一次没碎,那么剩下j-1次,剩下i个蛋

    我们也希望用剩下的次数和剩下的蛋在上面能确定的楼层数最大,所以是dp[i][j-1]

    加上扔蛋的这一次

    所以 dp[i][j]=dp[i-1][j-1]+dp[i][j-1]+1

    如果只有一个蛋,只能1层1层的试,dp[1][i]=i

    如果只有一层,dp[i][1]=1

    初始化和转移都跟 组合数C 很像

    C爆炸式增长,所以这个也是爆炸式增长

    论文里有证明

    也就是说当n很大的时候,i和j很小

    当n=2e9时,i和j只取到32就A了

    #include<cstdio>
    
    using namespace std;
    
    typedef long long LL;
    
    LL dp[33][33];
    
    void DP()
    {
        for(int i=1;i<=32;++i) dp[i][1]=1,dp[1][i]=i;
        for(int i=2;i<=32;++i)
            for(int j=2;j<=32;++j)
                dp[i][j]=dp[i][j-1]+dp[i-1][j-1]+1;
    }
    
    int main()
    {
        DP();
        int T;
        scanf("%d",&T);
        int n,m,ans;
        while(T--)
        {
            scanf("%d%d",&n,&m);
            ans=-1;
            for(int i=1;i<=32;++i)
                if(dp[m][i]>=n) { ans=i; break; }
            if(ans==-1) puts("Impossible");
            else printf("%d
    ",ans);
        }
    }
     
  • 相关阅读:
    Nginx平滑升级
    svn部署-linux
    svn服务备份与还原
    vmware exsi安装部署
    redis主从复制读写分离
    redis配置文件详解
    zabbix与agent端通信加密
    部署owa预览服务
    zabbix-3.4邮件报警
    centos7--zabbix3.4微信报警
  • 原文地址:https://www.cnblogs.com/TheRoadToTheGold/p/8453790.html
Copyright © 2011-2022 走看看