• CH5E07 划分大理石(背包dp+二进制拆分)


        传送门

        大意:

      有价值分别为1..6的大理石各a[1..6]块,现要将它们分成两部分,使得两部分价值之和相等,问是否可以实现。其中大理石的总数不超过20000。

     解题思路:

      妥妥的多重背包+二进制拆分,主要写一下二进制拆分存个档(儿时的噩梦)。

      总所周知,20,21,22,……2k-1从中挑选若干个相加可以得到0~2k-1中的任意数。那么将一个数s进行二进制拆分,首先要做的就是找到最大k满足2k-1<=s,设c=s-2k+1。显而易见20,21,……,2k-1,c可以从中挑选若干个数相加得到0~s中的任意数。这题要做优化就是从这个思路中来,拿价值为1的大理石举例,设有t1个价值为1的大理石,可以将t1拆分为20,21,22,……,2k-1,c,然后就可以将多重背包化为01背包去解决,每个数s可以化解出log(s)个,总复杂度o(nlogn)

      

    #include<bits/stdc++.h>
    using namespace std;
    int num[7][10086];
    bool bk[100086];
    int main()
    {
        int t[10];
        while(1){
            int sum=0;
            for(int i=1;i<=6;i++){
                scanf("%d",&t[i]);
                sum+=t[i]*i;
            }
            if(sum==0)    break;
            if(sum&1){
                cout<<"Can't"<<endl;continue;
            }
            sum/=2;for(int i=1;i<=sum;i++)    bk[i]=false;bk[0]=true;
            for(int i=1;i<=6;i++){
                int t1=0,t2=0;
                while(t[i]>=(1<<t1)){
                    num[i][t1]=(1<<t1);t1++;
                }
                if(t[i]-(1<<t1))    num[i][t1++]=t[i]-(1<<t1);
                for(int j=0;j<t1;j++){
                    for(int h=sum;h>=i*num[i][j];h--){
                        bk[h]|=bk[h-i*num[i][j]];
                    }
                }
            }
            if(bk[sum])    cout<<"Can"<<endl;
            else        cout<<"Can't"<<endl;
        }
    }
    View Code
  • 相关阅读:
    [转]使用Composer管理PHP依赖关系
    Php环境下载(PHPNow)安装
    精美的 ( Android, iPhone, iPad ) 手机界面设计素材和线框图设计工具
    八款强大的jQuery图片滑块动画插件
    JavaScript prototype.js提升JavaScript开发效率
    JS Message 网页消息提醒
    Vis.js图表插件
    动态算法学习
    GPS功能:百度路书自定义【轨迹回放】
    CSS美化页面滚动条
  • 原文地址:https://www.cnblogs.com/r138155/p/12663900.html
Copyright © 2020-2023  润新知