牛牛准备参加学校组织的春游, 出发前牛牛准备往背包里装入一些零食, 牛牛的背包容量为w。
牛牛家里一共有n袋零食, 第i袋零食体积为v[i]。
牛牛想知道在总体积不超过背包容量的情况下,他一共有多少种零食放法(总体积为0也算一种放法)。
输入包括两行
第一行为两个正整数n和w(1 <= n <= 30, 1 <= w <= 2 * 10^9),表示零食的数量和背包的容量。
第二行n个正整数v[i](0 <= v[i] <= 10^9),表示每袋零食的体积。
输出一个正整数, 表示牛牛一共有多少种零食放法。
3 10 1 2 4
8
三种零食总体积小于10,于是每种零食有放入和不放入两种情况,一共有2*2*2 = 8种情况。
Map.prototype.floorKey = function(key) {
let map = this;
let ans = null;
for(let k of map.keys()) {
if(k > key) {
break;
} else {
ans = k;
}
}
return ans;
}
// 根据数据量描述,2^30>10^8,采用分而治之的思路
function ways(arr, bag) {
let len = arr.length;
if(arr == null || len == 0) {
return 0;
}
if(len == 1) {
return arr[0] <= bag ? 2: 1;
}
let mid = (len - 1) >> 1;
let lmap = new Map();
let ways = process(arr, 0, 0, mid, bag, lmap);
let rmap = new Map();
ways += process(arr, mid + 1, 0, len - 1, bag, rmap);
// 对rmap进行手动排序,以模拟TreeMap,这里先不用手动实现有序表,太冗长
rmap = new Map([...rmap.entries()].sort((a, b) => a[0] - b[0]));
let rpre = new Map();
let pre = 0;
for(let [key, value] of rmap.entries()) {
pre += value;
rpre.set(key, pre); // 方法前缀和map
}
for(let [lweight, lways] of lmap.entries()) {
let floor = rpre.floorKey(bag - lweight);
if(floor != null) {
let rways = rpre.get(floor);
ways += lways * rways;
}
}
return ways + 1; // process中没考虑都不选的情况,所以方法加1
}
function process(arr, index, w, end, bag, map) {
if(w > bag) {
return 0;
}
if(index > end) {
if(w != 0) {
if(!map.has(w)) {
map.set(w, 1);
} else {
map.set(w, map.get(w) + 1);
}
return 1;
} else {
return 0;
}
} else {
let ways = process(arr, index + 1, w, end, bag, map);
ways += process(arr, index + 1, w + arr[index], end, bag, map);
return ways;
}
}
// 牛客js-v8 处理输入输出
let line1 = readline();
let line2 = readline();
let [n, w] = line1.split(' ').map(x => +x);
let v = line2.split(' ').map(x => +x);
let res = ways(v, w);
print(res);