题目
https://www.luogu.com.cn/problem/P5194
思路
\(n \leq 1000\)的范围很吓人,但是按照【每个砝码的质量至少等于前面两个砝码的质量的和】的规则,打表可知n在50时总重量就已经超过了\(2^{30}\)。
于是大胆得出\(n \leq 50\)
因为数据不下降,于是将n个砝码从中间断开,分别搜索出前后\(n/2\)个砝码对应组成的总重量方案数\(a_{cnt}\)和\(b_{tot}\)。
将\(b_{tot}\)排序,枚举\(a_{cnt}\)中的每一个方案,在\(b_{tot}\)中用寻找第一个小于等于c-a[i]的方案数,不断更新答案即可。
dfs复杂度\(O(2^{n/2})\),二分查找复杂度\(O(nlogn)\)
总复杂度\(O(2^{n/2+1}+nlogn)\)
Code
#include<iostream>
#include<cstdio>
#include<algorithm>
const int maxn = (1 << 25) + 10;
const int maxm = 50;
int a[maxn], b[maxn];//储存两段搜索的方案数
int num[maxm];
int n, c, ans;
int cnt, tot;
void dfs1(int x, int sum, int border) {
if (sum > c) return;
if (x > border) {
a[++cnt] = sum;
return;
}
dfs1(x + 1, sum + num[x], border);
dfs1(x + 1, sum, border);
}
void dfs2(int x, int sum, int border) {
if (sum > c) return;
if (x > border) {
b[++tot] = sum;
return;
}
dfs2(x + 1, sum + num[x], border);
dfs2(x + 1, sum, border);
}
int main() {
scanf("%d%d", &n, &c);
for (int i = 1; i <= n; i++) scanf("%d", &num[i]);
dfs1(1, 0, n / 2);
dfs2(n / 2 + 1, 0, n);
std::sort(b + 1, b + 1 + tot);
for (int i = 1; i <= cnt; i++) {
int curr = std::upper_bound(b + 1, b + 1 + tot, c - a[i]) - b - 1;
ans = std::max(ans, a[i] + b[curr]);
}
std::cout << ans;
return 0;
}
标签:折半,洛谷,Scales,int,sum,tot,砝码,return,border
From: https://www.cnblogs.com/MrWangnacl/p/16775278.html