zoukankan      html  css  js  c++  java
  • 洛谷1490 买蛋糕(搜索+剪枝)

    对于前面的一半答案,有个显然的结论
    取1,2,4,8,16……2n是最优的,当且仅当输入的n大于2(i-1),小于2i次时取得最小的答案。对于第二种,我们有两种解法,DP和爆搜,这题提供爆搜解法。看到题解区有一个爆搜,不过他代码跑起来有点慢,这里还提供一个剪枝,比如现在我们最多可以将k这个数之前的数字全部表示出来,那么下一个我们最大可以取到k+1,那么可以表示的最大数就是2k+1,由此,如果我们还能取m个数,那么2m*(k+1)-1就是我们最终可以取到的最大的可以表示的数字了,如果仍然比n小,我们就可以退出循环。此外,记录答案时,我们可以退一层来表示,具体看代码,61ms还算挺快

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    using namespace std;
    int re(){
        char c=getchar();int all=0,pd=1;
        for(;c>'9'||c<'0';c=getchar()) if(c=='-') pd=-1;
        while(c>='0'&&c<='9') all=all*10+c-'0',c=getchar();return all*pd;
    }const int N=1005;int qpow[N],ans,f[N],a[N],n;
    void dfs(int x,int last,int al){
        if(al*2+1>=n){ans+=min(al-a[a[0]]+1,al*2+2-n);return;}
        //比如我们有n=20,可以表达的最大数字为13,前面已经取了1,2,4,7,那么理论不考虑前面数字大小的情况下。
        //我们可以取7,8,9,10,11,12,13,14共8种,但是由于7和7重合,所以我们只有7种。
        //这个左侧表示的是从前面数字大小的情况来考虑,后面的是从最大能取的情况考虑
        if((al+1)*qpow[x]-1<n&&al>=2) return;
        for(int i=last;i<=al+1;i++){ 
            a[++a[0]]=i;dfs(x-1,i+1,al+i);a[a[0]--]=0;
        }
    }
    int main(){
        n=re();qpow[0]=1;for(int i=1;i<=30;i++) qpow[i]=qpow[i-1]*2;
        for(int i=0;i<=31;i++) if(n>=qpow[i]&&n<qpow[i+1])
        {printf("%d ",i+1);;dfs(i+1,1,0);printf("%d
    ",ans);return 0;}
    }
    
  • 相关阅读:
    LVS负载均衡NAT模式实现
    Linux-ftp服务搭建
    Keepalived配置详解
    Keepalived高可用概念篇
    Nginx-http_proxy_module模块
    Nginx-keepalived+Nginx实现高可用集群
    Oracle注入之带外通信
    Oracle基于延时的盲注总结
    Oracle基于布尔的盲注总结
    Oracle报错注入总结
  • 原文地址:https://www.cnblogs.com/BLUE-EYE/p/9538238.html
Copyright © 2011-2022 走看看