题解:P9824 [ICPC 2020 Shanghai R] Fountains
观察:固定选择的区间后,如何使总代价最小?把所有区间按
这里我们说一个区间
转化:于是先把所有区间从大到小排序,考虑 dp。
你发现此时我们只关心:第一,选取了多少个区间;第二,哪些
设
观察:发现,若
所有的
预处理出状态
#define int ll
const int N = 10, P = 998244353;
typedef __int128 LL;
int n, a[N];
map <LL, int> dp[N * N][N * N];
struct itv {
int l, r, x;
bool operator < (const itv &t) const {
return x > t.x;
}
} arr[N * N];
int sum[N];
signed main() {
cin >> n;
R(i, 1, n) {
cin >> a[i];
sum[i] = sum[i - 1] + a[i];
}
int m = 0;
R(i, 1, n) {
int s = 0;
R(j, i, n) {
s += a[j];
arr[++m] = {i, j, s};
}
}
sort(arr + 1, arr + m + 1);
dp[0][0][0] = 0;
auto fill = [&](int i, int j, LL s, int val) {
if (!dp[i][j].count(s)) {
dp[i][j][s] = val;
} else {
dp[i][j][s] = max(dp[i][j][s], val);
}
} ;
auto id = [&](int l, int r) {
return (l - 1) * n + r;
} ;
LL all = 0; int alls = 0;
R(l, 1, n) {
R(r, l, n) {
all |= (__int128(1) << id(l, r));
alls += sum[r] - sum[l - 1];
}
}
R(i, 0, m - 1) {
R(j, 0, i) {
for (auto [s, val] : dp[i][j]) {
fill(i + 1, j, s, val);
LL st = 0; int d = 0;
R(l, 1, n) {
R(r, l, n) {
if (s >> id(l, r) & 1) {
st |= (__int128(1ll) << id(l, r));
} else if (l <= arr[i + 1].l && r >= arr[i + 1].r) {
st |= (__int128(1ll) << id(l, r));
d += sum[arr[i + 1].r] - sum[arr[i + 1].l - 1];
}
}
}
// assert((st & s) == s);
fill(i + 1, j + 1, st, val + d);
}
}
}
R(i, 1, m) {
int mx = 0;
for (auto [s, val] : dp[m][i]) {
mx = max(mx, val);
}
cout << alls - mx << endl;
}
return 0;