47 SP估算Estimation 题解
Estimation
题面
给定一个长度为 N 的整数数组 A,你需要创建另一个长度为 N 的整数数组 B,数组 B 被分为 M 个连续的部分,并且如果 i 和 j 在同一个部分,则 \(B[i]=B[j]\)。
如果要求数组 B 能够满足 \(\sum |A_i - B_i|\) 最小,那么最小值是多少,请你输出这个最小值。
\(1 \le N \le 2000, 1 \le M \le \min(N,25)\)
题解
这道题如果你知道怎么动态求第 \(k\) 大,那么应该就比较简单了
设 \(f(i,j)\) 表示将前 \(i\) 个数,分成 \(j\) 段的最小代价
有转移
\[f(i,j) = \min_{0 \le k \le i - 1} \{ f(k,j - 1) + cost(k + 1, j) \}
\]
如果能够预处理 \(cost\) 那么这个转移就是 \(O(N^2M)\) 的,可以接受
想办法预处理 \(cost\) ,这个可以联想一下“货仓选址”,和那个是一样的,所以我们需要求出 \(i \sim j\) 的中位数,暴力求是 \(O(N \log N)\) 的,带上外层循环,显然超时
所以这里要用到一个动态求第 \(k\) 大的技巧,也就是用对顶堆维护第 \(k\) 大
可以在 \(O(N^2 \log N)\) 的时间复杂度内预处理出 \(cost\)
然后就是这道题有点卡常,优先队列的快速清空可以用 .swap(tmp)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <queue>
#include <unordered_map>
using namespace std;
const int N = 2e3 + 10, M = 30;
int n, m, f[N][M];
int a[N], val[N][N], cost[N][N];
unordered_map <int, int> mp;
int rd () {
int res = 0, f = 1;
char c = getchar ();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar ();
}
while (c >= '0' && c <= '9') {
res = (res << 1) + (res << 3) + (c ^ 48);
c = getchar ();
}
return res * f;
}
struct heap_pair {
int cnt;
priority_queue <int, vector <int>, greater<int> > mn;
priority_queue <int> ma;
void clear () {
priority_queue <int, vector <int>, greater<int> > mn2;
priority_queue <int> ma2;
mn.swap (mn2), ma.swap (ma2);
cnt = 0;
}
void push (int x) {
if (ma.empty () || x <= ma.top ()) ma.push (x);
else mn.push (x);
cnt ++;
int k = (cnt + 1) >> 1;
if ((int)ma.size () < k) {
ma.push (mn.top ());
mn.pop ();
}
if ((int)ma.size () > k) {
mn.push (ma.top ());
ma.pop ();
}
}
} q;
int main () {
while (n = rd (), m = rd ()) {
if (!n && !m) break;
q.clear ();
for (int i = 1; i <= n; i ++) {
a[i] = rd();
mp[a[i]] = i;
}
//预处理val, val[i][j] 表示 [1~j abs (a[j] - a[i])]
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= n; j ++) {
val[i][j] = abs (a[j] - a[i]) + val[i][j - 1];
}
}
//预处理cost, cost[i][j] 表示将 i~j 分为一段的最小代价
for (int i = 1; i <= n; i ++) {
q.clear ();
for (int j = i; j <= n; j ++) {
q.push (a[j]);
int mid = q.ma.top ();
int pos = mp[mid];
cost[i][j] = val[pos][j] - val[pos][i - 1];
}
}
memset (f, 0x3f, sizeof f);
f[0][0] = 0;
for (int i = 1; i <= n; i ++) {
for (int j = 1; j <= min (i, m); j ++) {
for (int k = i - 1; k >= 0; k --) {
f[i][j] = min (f[i][j], f[k][j - 1] + cost[k + 1][i]);
}
}
}
printf ("%d\n", f[n][m]);
}
return 0;
}

浙公网安备 33010602011771号