https://vjudge.net/problem/HDU-4261
https://www.acwing.com/problem/content/332/
题解:
首先假如k=1,那么这个值很好找,让B数组取值A的中位数即可。
令cost[a][b]表示从B[a]~B[b] 划分为一组,得到的Σ(abs(A[i]-b[i]) (i∈[a,b]) 的最小值
显然,类似于背包问题,设dp[i][j] 为 第1~i个数分为k个连续部分得到的结果的最小值
dp[i][j] = min(dp[k][j-1]+cost[k+1][j]) k∈[1,i)
接下来就是如何处理的到cost数组的时候了
若是需要递推的找到一段数组的中位数,我们可以维护两个堆,一个是大根堆,一个是小根堆,每次插入数字保持大根堆和小根堆的大小只差不超过1,此时就可以轻松找到中位数了
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e3 + 7;
const int INF = 0x3f3f3f3f;
int n, k;
int num[maxn], cost[maxn][maxn], dp[maxn];
struct node1 { //大根堆
int val[maxn], tot;
void init() {
//memset(val, 0, sizeof(val));
tot = 0;
}
void push(int x) {
val[++tot] = x;
int now = tot;
while (now >> 1) {
if (val[now >> 1] > val[now])
break;
swap(val[now >> 1], val[now]);
now >>= 1;
}
}
int get() {
return val[1];
}
void pop() {
swap(val[1], val[tot]);
tot--;
int now = 1, nxt = 2;
while (nxt<=tot) {
if (nxt<tot&&val[nxt + 1]>val[nxt])
nxt++;
if (val[nxt] < val[now])
break;
swap(val[nxt], val[now]);
now = nxt; nxt *= 2;
}
}
int size() {
return tot;
}
}Q1;
struct node2 { //小根堆
int val[maxn], tot;
void init() {
//memset(val, 0, sizeof(val));
tot = 0;
}
void push(int x) {
val[++tot] = x;
int now = tot;
while (now >> 1) {
if (val[now >> 1] < val[now])
break;
swap(val[now >> 1], val[now]);
now >>= 1;
}
}
int get() {
return val[1];
}
int size() {
return tot;
}
void pop() {
swap(val[1], val[tot]);
tot--;
int now = 1, nxt = 2;
while (nxt <= tot) {
if (nxt<tot&&val[nxt + 1]<val[nxt])
nxt++;
if (val[nxt] > val[now])
break;
swap(val[nxt], val[now]);
now = nxt; nxt *= 2;
}
}
}Q2;
void make_cost() {
for (int i = 1; i <= n; i++) {
Q1.init();
Q2.init(); //小根堆,适合大的那边使用
cost[i][i] = 0;
int sum1 = 0, sum2 = 0;
Q2.push(num[i]);
sum2 += num[i];
for (int j = i + 1; j <= n; j++) {
if (num[j] >= Q2.get())
Q2.push(num[j]), sum2 += num[j];
else
Q1.push(num[j]), sum1 += num[j];
if (Q2.size() - Q1.size() > 1) {
sum1 += Q2.get();
sum2 -= Q2.get();
Q1.push(Q2.get());
Q2.pop();
}
else if (Q1.size() - Q2.size() > 1) {
sum2 += Q1.get();
sum1 -= Q1.get();
Q2.push(Q1.get());
Q1.pop();
}
cost[i][j] = sum2 - sum1;
if (Q1.size() > Q2.size())
cost[i][j] += Q1.get();
else if (Q2.size() > Q1.size())
cost[i][j] -= Q2.get();
}
}
}
int main() {
while (cin >> n >> k, n) {
for (int i = 1; i <= n; i++)
scanf("%d", num + i);
make_cost();
memset(dp, INF, sizeof(dp));
dp[0] = 0;
for (int cnt = 1; cnt <= k; cnt++) {
for (int i = n; i; i--) { //这个要递减
for (int j = 0; j < i; j++) {
dp[i] = min(dp[i], dp[j] + cost[j + 1][i]);
}
}
}
cout << dp[n] << endl;
}
}