题解:只按照假设有30个数的情况来算
如果单纯直接枚举的话,那么就是 30 ∗ 29 ∗ 28 ∗ ⋯ ∗ 15 30 * 29 * 28 * \dots * 15 30∗29∗28∗⋯∗15,这样的话时间复杂度直接爆炸。
那么考虑折半枚举,考虑从前面15个数中选出了
i
i
i个数,那么必然就得从后面15个数中选出
j
=
15
−
i
j=15-i
j=15−i个数,这样复杂度是
∑
i
=
0
15
C
15
i
∗
C
15
15
−
i
{\textstyle \sum_{i=0}^{15}} C_{15}^{i}*C_{15}^{15-i}
∑i=015C15i∗C1515−i
这样也是会T掉的,但是考虑一个情况是这样的,对于一个数
s
u
m
sum
sum,并且
a
+
b
=
s
u
m
a+b=sum
a+b=sum,现在想让
∣
a
−
b
∣
|a-b|
∣a−b∣达到最小值,最直观的想法就是
a
a
a和
b
b
b相等,不能相等也就尽量让
a
、
b
a、b
a、b中较小的那个数往
s
u
m
/
2
sum/2
sum/2上凑,也就是说我们从前面15个数中选出了
i
i
i个数的和之后,然后直接二分从后面15个数中选出
j
=
15
−
i
j=15-i
j=15−i个数中最接近($sum/2 -
前
面
15
个
数
中
选
出
了
前面15个数中选出了
前面15个数中选出了i$个数的和),使得时间复杂度降低到:
∑
i
=
0
15
C
15
i
∗
3
{\textstyle \sum_{i=0}^{15}} C_{15}^{i}*3
∑i=015C15i∗3
#include <bits/stdc++.h>
using namespace std;
#define db double
#define ll long long
#define pii pair<int,int>
#define rush() int T; cin >> T; while (T--)
const int N = 1e5 + 5;
const int M = (N << 2);
const int P = 1e9 + 7;
class Solution {
public:
int n;
void init(vector<vector<int> > &now, vector<int> &nums)
{
for (int i = 0; i < (1 << n); i ++) {
int dig = __builtin_popcount(i), sum = 0;
for (int j = 0; j < n; j ++) if (i >> j & 1) sum += nums[j];
now[dig].emplace_back(sum);
}
}
int minimumDifference(vector<int>& nums)
{
n = nums.size() / 2;
vector<int> p_nums, s_nums;
int p_sum, s_sum, sum = 0;
for (int i = 0; i < nums.size(); i ++) {
if (i < n) p_nums.emplace_back(nums[i]), p_sum += nums[i];
else s_nums.emplace_back(nums[i]), s_sum += nums[i];
sum += nums[i];
}
int mid = sum / 2;
vector<vector<int> > pre(n + 1), suf(n + 1);
init(pre, p_nums);
init(suf, s_nums);
int ans = 0x3f3f3f3f;
for (int i = 0; i <= n; i ++) {
int j = n - i;
sort(suf[j].begin(), suf[j].end());
for (auto &x : pre[i]) {
int idx = min((int)suf[j].size() - 1, (int)(lower_bound(suf[j].begin(), suf[j].end(), mid - x) - suf[j].begin()));
for (int k = -1; k < 2; k ++) {
if (idx + k >= 0 && idx + k < suf[j].size()) ans = min(ans, abs(2 * x + 2 * suf[j][idx + k] - sum));
}
}
}
return ans;
}
};
博客探讨了一种高效的算法策略,用于将一个数组分成两个子数组,以最小化它们的和之差。文章通过分析指出,简单的枚举方法会导致时间复杂度爆炸,进而提出使用折半枚举结合二分查找的方法,降低了复杂度。具体实现中,通过从前面的数中选择一部分,然后在后面的数中找到最接近目标和的组合,从而达到最小化差值的目标。
&spm=1001.2101.3001.5002&articleId=121230758&d=1&t=3&u=375c11a7168f41b18a01c7f482c12dcb)
4722

被折叠的 条评论
为什么被折叠?



