高维前缀和
这东西好像可以说是 sos dp,我也不太懂。
引入
对于 \(i\) 求 \(\sum_{j \subset i} a_j\)
- 直接枚举子集 \(O(n3^n)\),直接爆炸了。
- sos dp,\(O(n2^n)\),一下就好了。
代码:
for(int j = 0; j < n; j ++) {
for(int i = 0; i < 1 << n; i ++) {
if(i >> j & 1) f[i] += f[i ^ 1 << j];
}
}
理解一下:其实就是对于每一层的 \(j\),来看所有的 \(i\),然后由于 \(i\) 从小到大进行遍历的,所以说 \(f_i\) 是 \(j - 1\) 时的值,那么增加 \(j\) 这一层的变化量就到了 \(j\) 这一层的 \(f_i\)。
反正总结一句话:固定维度增加这一维的变化量。
例题
arc100_e
考试题,这不是直接上个 sos dp 秒了吗?只是改成了记录最大值 + 次大值吗?
竟然是个蓝?
所以强的不是我,是板子和前人的思路。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ld = long double;
using ull = unsigned long long;
using ai2 = array<int, 2>;
const int N = 18;
int n, a[1 << N], ans;
ai2 f[1 << N];
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for(int i = 0; i < 1 << n; i ++) cin >> a[i], f[i] = ai2{a[i], -0x3f3f3f3f};
for(int j = 0; j < n; j ++) {
for(int i = 0; i < 1 << n; i ++) {
if(i >> j & 1) {
vector<int> vec = {f[i][0], f[i][1], f[i ^ 1 << j][0], f[i ^ 1 << j][1]};
sort(vec.begin(), vec.end(), greater<>());
f[i] = ai2{vec[0], vec[1]};
}
}
}
for(int i = 1; i < 1 << n; i ++) {
ans = max(ans, f[i][0] + f[i][1]);
cout << ans << '\n';
}
return 0;
}

浙公网安备 33010602011771号