UPC10755 You Like Cake
题目描述
双十一就要来啦!而Yuno刚刚获得了一笔X元的奖金。那么是不是应该清空下购物车呢?
购物车总共有N个物品,每个物品的价格为Vi,Yuno想尽可能地把手头的奖金给花光,所以她要精心挑选一些商品,使得其价格总和最接近但又不会超过奖金的金额。那么Yuno最后最少可以剩下多少钱呢?
购物车总共有N个物品,每个物品的价格为Vi,Yuno想尽可能地把手头的奖金给花光,所以她要精心挑选一些商品,使得其价格总和最接近但又不会超过奖金的金额。那么Yuno最后最少可以剩下多少钱呢?
输入
第一行,两个正整数N和X。
第二行,N个正整数Vi表示第i个物品的价格。
第二行,N个正整数Vi表示第i个物品的价格。
输出
输出一个整数,表示Yuno最后最少可以剩下的钱数。
样例输入
4 50
1 2 3 4
样例输出
40
提示
对于100的数据,N≤40,X,Vi≤109
以前做过的题…… ,考试周没写代码结果考完训练的时候就想不出来怎么写了,菜爆了。
2^40很大,但是分成两半变成2^20就是枚举可以接受的复杂度了。分别算出左半边和右半边各自的各种组合,然后对于左边每一种情况在右边进行二分,寻找最优解
i&(i-1) //将数字二进制中的最右边一个1及其后面的位取反
#include "bits/stdc++.h" using namespace std; typedef long long ll; const int maxn = 1 << 21; ll v[maxn]; ll lv[maxn], rv[maxn]; int main() { freopen("input.txt", "r", stdin); ll n, x; cin >> n >> x; int mid = n >> 1; ll ln = 1 << mid; ll rn = 1 << (n - mid); ll tmp; for (int i = 0; i < mid; i++) { cin >> v[1 << i]; } for (int i = 1; i <= ln; i++) { tmp = i & (i - 1); lv[i] = v[i ^ tmp] + lv[tmp]; } for (int i = 0; i < n - mid; i++) { cin >> v[1 << i]; } for (int i = 1; i <= rn; i++) { tmp = i & (i - 1); rv[i] = v[i ^ tmp] + rv[tmp]; } sort(rv, rv + rn); ll ans = -1; ll temp; int pos; for (int i = 0; i <= ln; i++) { if (lv[i] > x) continue; temp = x - lv[i]; pos = upper_bound(rv, rv + rn, temp) - rv - 1; ans = max(ans, lv[i] + rv[pos]); } cout<<x-ans<<endl; return 0; }