洛谷P4799 [CEOI2015 Day2]世界冰球锦标赛 题解 折半搜索+二分
题目链接:https://www.luogu.com.cn/problem/P4799
解题思路:
如果暴搜时间复杂度是 \(O(2^{40})\),所以考虑折半搜索。
前一半搜索的时候记录好所有的状态,然后对这些状态对应的价格排序。
后一半搜索的时候到边界条件时用二分确定前一半的数量。
时间复杂度降到 \(O(2^{20} \cdot 20 \cdot 2)\)。
示例代码如下:
#include <bits/stdc++.h>
using namespace std;
int n;
long long m, a[44], b[1<<21], cnt, ans;
void dfs1(int id, long long tmp) {
if (tmp > m) return;
if (id > n/2) {
b[cnt++] = tmp;
return;
}
dfs1(id+1, tmp);
dfs1(id+1, tmp+a[id]);
}
void dfs2(int id, long long tmp) {
if (tmp > m) return;
if (id > n) {
int p = upper_bound(b, b+cnt, m-tmp) - b;
ans += p;
return;
}
dfs2(id+1, tmp);
dfs2(id+1, tmp+a[id]);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i ++) cin >> a[i];
dfs1(1, 0);
sort(b, b+cnt);
dfs2(n/2+1, 0);
cout << ans << endl;
return 0;
}