码迷,mamicode.com
首页 > 其他好文 > 详细

You Like Cake(超大01背包模板题)

时间:2019-01-17 21:53:20      阅读:303      评论:0      收藏:0      [点我收藏+]

标签:std   枚举   typedef   space   输入   continue   描述   using   返回   

You Like Cake

题目描述

双十一就要来啦!而Yuno刚刚获得了一笔X元的奖金。那么是不是应该清空下购物车呢?
购物车总共有N个物品,每个物品的价格为Vi,Yuno想尽可能地把手头的奖金给花光,所以她要精心挑选一些商品,使得其价格总和最接近但又不会超过奖金的金额。那么Yuno最后最少可以剩下多少钱呢?

输入

第一行,两个正整数N和X。
第二行,N个正整数Vi表示第i个物品的价格。

输出

输出一个整数,表示Yuno最后最少可以剩下的钱数。

样例输入

4 50
1 2 3 4

样例输出

40

提示

对于100的数据,N≤40,X,Vi≤109

背包容量过大采用折半之后二进制枚举子集,再二分查找

upper_bound返回的是第一个大于查找的数的位置

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[25],b[25];
ll s[(1<<21)+1],f[(1<<21)+1];
int main(){
    int n;
    ll m;scanf("%d%lld",&n,&m);
    for(int i=1;i<=n;++i){
        if(i<=n/2){
            scanf("%lld",&a[i]);
        }
        else scanf("%lld",&b[i-n/2]);
    }
    int k=n/2;
    int pos=0;
    for(int i=0;i<(1<<k);++i){
        for(int j=1;j<=k;++j){
            if(i&(1<<(j-1))){
                s[pos]+=a[j];
            }
        }
        pos++;
    }
    int len=(int)(unique(s,s+pos)-s);
    sort(s,s+len);
    pos=0;k=n-k;
    for(int i=0;i<(1<<k);++i){
        for(int j=1;j<=k;++j){
            if(i&(1<<(j-1))){
                f[pos]+=b[j];
            }
        }
        pos++;
    }
    ll ans=0;
    int op;
    for(int i=0;i<pos;++i){
            if(m<f[i]) continue;
            op=upper_bound(s,s+len,m-f[i])-s;
            op--;
            if(op>=0){
               ans=max(ans,s[op]+f[i]);
            }
    }
    printf("%lld\n",m-ans);
    return 0;
}

You Like Cake(超大01背包模板题)

标签:std   枚举   typedef   space   输入   continue   描述   using   返回   

原文地址:https://www.cnblogs.com/smallocean/p/10284664.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!