ICPC2020上海站F Fountains 状压
题意:给定长为\(n\)的序列,定义区间\([l,r]\)的权值\(C(l,r)\)为\([l,r]\)中所有元素的和,现在试选择\(k\)个区间\([l_i, r_i](1\leq l_i\leq r_i\leq n)\),使得
$$\sum_{1\leq L\leq R\leq n} [C(L, R) - \max_{L\leq l_i \leq r_i \leq R } C(l_i, r_i)]$$最小,对\(k=1, 2, 3..., n*(n+1)/2\)作出回答,且\(n\leq 9\)
不妨假定已经选择\(k\)个区间,考虑怎么使得权值和最小
显然,将\(k\)个区间按权值大小从大到小排序,所有的\([L, R]\)区间会按此顺序选择第一个被它包含的区间\([l_i, r_i]\)
换而言之,即将\(k\)个区间从大到小排序后,依次考虑,在仍未选择的区间\([L, R]\)中,所有能选择\([l_i, r_i]\)的区间一定会选择此区间
可以\(dp\),状态为已经选择了\(k\)个区间,及仍未选择的区间
仍未选择的区间可以通过\((r_1, r_2, ..., r_n)\)表示,其中\(r_i\)表示\([i, i], [i,i+1], ..., [i, r_i]\)仍未选择
由于\(r_1\leq r_2 \leq ... \leq r_n\),状态数并不大(最大375544),并且本题有6s时限,hash都不用,开个map即可过
#include <map>
#include <vector>
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
#define l first
#define r second
#define ll long long
#define mp make_pair
#define pii pair <int, int>
#define rep(io, st, ed) for(int io = st; io <= ed; io ++)
#define drep(io, ed, st) for(int io = ed; io >= st; io --)
const int sid = 1e6 + 5;
int n, tt[105];
ll all, ans[105], s[105];
map <ll, ll> now, pre;
vector <pii> seg;
ll encode(int *a) {
ll ret = 0;
drep(i, n + 1, 1) ret = ret * 10 + a[i];
return ret;
}
void decode(ll v, int *a) {
rep(i, 1, n) a[i] = v % 10, v /= 10;
a[n + 1] = v;
}
int main() {
cin >> n;
rep(i, 1, n) cin >> s[i], s[i] += s[i - 1];
rep(L, 1, n) rep(R, L, n) seg.push_back(mp(L, R)), all += s[R] - s[L - 1];
sort(seg.begin(), seg.end(), [](pii &a, pii &b) { return s[a.r] - s[a.l - 1] >= s[b.r] - s[b.l - 1]; } );
rep(i, 1, n) tt[i] = n; now[encode(tt)] = 0;
rep(si, 0, seg.size() - 1) {
int l = seg[si].l, r = seg[si].r;
ll v = s[r] - s[l - 1];
pre = now; now.clear();
for(auto x : pre) {
ll pv = x.second; decode(x.first, tt);
//不选择
now[x.first] = max(now[x.first], pv);
//选择
rep(i, 1, l) if(tt[i] >= r) pv += (tt[i] - r + 1) * v, tt[i] = r - 1;
tt[n + 1] ++; ll to = encode(tt);
now[to] = max(now[to], pv);
}
}
for(auto x : now) {
decode(x.first, tt);
ans[ tt[n + 1] ] = max(ans[ tt[n + 1] ], x.second);
}
rep(i, 1, n * (n + 1) / 2) printf("%lld\n", all - ans[i]);
return 0;
}
喵喵喵?喵喵喵! 喵喵喵......