You Like Cake(超大01背包模板題)
阿新 • • 發佈:2019-01-18
ace printf 子集 二分查找 雙十一 mes class 購物 else
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背包模板題)