• bzoj 3965: [WF2011]Pyramids


    Description

    如果你有足够的石块,那么建一座金字塔绝不算难事。举个例子,在一块平地上,我们铺一个10*10的矩形,然后在10*10的矩形上面铺一个9*9的,然后8*8的……以此类推,直到顶上1*1。这个金字塔有10层,我们称这类金字塔为“高金字塔”。
    如果你认为这样的金字塔太陡了,那么我们有办法让他看上去坡度平缓一些。比如,在10*10的矩形上,我们铺一个8*8的矩形,然后是6*6的……这样的金字塔只有5层了,大约为底座边长的一半。我们称之为“矮金字塔”。
    很久以前,一位法老从父亲那儿继承了一大堆用于搭建金字塔的石块。他决定用这些石块搭建一座金字塔——每个石块都必须用上。建筑师告诉他,这样的要求不一定能实现。例如,如果你有10块石头,那么可以搭一个底座为3的矮金字塔;如果有5块石头,那么就搭一个底座为2的高金字塔。如果你有7块石头呢?不幸的是,确实找不出一种搭金字塔的方案了。
    思考再三后,法老决定放低要求——搭不止一座金字塔。但是仍然要满足如下几个条件:
    1.所有石块都必须用上;
    2.金字塔数要尽可能少;
    3.所有金字塔两两不同;
    4.金字塔至少包含两层,即底座为1的金字塔和底座为2的矮金字塔是不允许的;
    5.满足以上4点的基础上,最大的金字塔要尽可能大(大定义为用的石块数多);
    6.满足以上5点的基础上,次大的金字塔要尽可能大;
    7.以此类推。。
    你能求出最好的搭金字塔方案么?或者告诉法老这是做不到的。
    金字塔只有300多种,先做一次bitset优化的0-1背包(保证条件1.3.4.),然后对每个询问搜索出条件2.的最优解(处理出哪些n可以用1到3个拼出,其余则只能>=4,用于最优性剪枝),通过搜索顺序保证条件5.6.7.
    #include<cstdio>
    #include<algorithm>
    #include<bitset>
    int s1[1007],s2[1007];
    struct item{
        int v,a,t;
        bool operator<(item x)const{return v!=x.v?v<x.v:t<x.t;}
    }is[327],ps[327],ps1[327];
    std::bitset<1000007>f[327];
    int ip=0,pp,mf[1000007];
    void dfs(int n,int w,int t){
        if(t+mf[n]>=pp)return;
        if(!n){
            pp=t;
            for(int i=0;i<t;++i)ps[i]=ps1[i];
        }
        if(!w)return;
        if(n>=is[w].v&&f[w-1].test(n-is[w].v))ps1[t]=is[w],dfs(n-is[w].v,w-1,t+1);
        dfs(n,w-1,t);
    }
    int main(){
        s1[1]=s2[1]=1;
        for(int i=2;i<=500;++i){
            s1[i]=s1[i-1]+i*i;
            s2[i]=s2[i-2]+i*i;
        }
        for(int i=2;s1[i]<=1000000;++i)is[++ip]=(item){s1[i],i,1};
        for(int i=3;s2[i]<=1000000;++i)is[++ip]=(item){s2[i],i,0};
        std::sort(is+1,is+ip+1);
        f[0].set(0);
        for(int i=1;i<=ip;++i)f[i]=f[i-1]|f[i-1]<<is[i].v;
        for(int i=1;i<=ip;++i){
            int x=is[i].v;
            if(!mf[x])mf[x]=1;
        }
        for(int i=1;i<=ip;++i){
            for(int j=i+1;j<=ip;++j){
                int x=is[i].v+is[j].v;
                if(x<=1000000&&!mf[x])mf[x]=2;
            }
        }
        for(int i=1;i<=ip;++i){
            for(int j=i+1;j<=ip;++j){
                for(int k=j+1;k<=ip;++k){
                    int x=is[i].v+is[j].v+is[k].v;
                    if(x<=1000000&&!mf[x])mf[x]=3;
                }
            }
        }
        for(int i=1;i<=1000000;++i)if(!mf[i])mf[i]=4;
        for(int _t=1,n;;++_t){
            if(scanf("%d",&n)!=1||!n)return 0;
            if(!f[ip].test(n))printf("Case %d: impossible
    ",_t);
            else{
                printf("Case %d:",_t);
                pp=10000;
                dfs(n,ip,0);
                for(int i=0;i<pp;++i)printf(" %d%c",ps[i].a,"LH"[ps[i].t]);
                puts("");
            }
        }
    }
  • 相关阅读:
    jquery之实例应用
    jquery之文档操作
    jquery之css操作
    jquery属性的操作
    jquery筛选器
    jquery选择器之表单选择表单对象属性
    jquery选择器之属性选择器
    jquery选择器之子元素
    数位dp基础
    Leetcode 5195. 最长快乐字符串(贪心)
  • 原文地址:https://www.cnblogs.com/ccz181078/p/7009436.html
Copyright © 2020-2023  润新知