#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1600 + 10;
int s[N][N]; // 决策点
LL w[N][N], f[N][N];
LL S[N];
int a[N];
int n, m;
// f[i][j] 表示前 i 个村庄建 j 个邮局最小花费
// w[i][j] 表示第 i 个村庄和第 j 个村庄间建 1 个邮局的最少花费
// s[i][j] 表示前 i 个村庄建 j 个邮局最小花费与建 j - 1 个邮局的决策点
// a <= b <= c <= d
// w[a][b] + w[c][d] <= w[a][d] + w[b][c] 满足四边形不等式, 即满足决策点 s 单调
// 区间单调 : a <= b <= c <= d
// s[b][c] <= s[a][d]
// s[i][j - 1] <= s[i][j] <= s[i + 1][j]
int main() {
memset(f, 0x3f, sizeof(f));
scanf("%d %d", &n, &m);
if(m >= n) {
printf("0");
return 0;
}
for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort(a + 1, a + n + 1);
for(int i = 1; i <= n; i++) S[i] = S[i - 1] + a[i];
for(int i = 1; i <= n; i++) {
for(int j = i; j <= n; j++) {
// 计算 w
int mid = (i + j) >> 1;
w[i][j] = (mid - i) * a[mid] - (S[mid - 1] - S[i - 1]) + (S[j] - S[mid]) - (j - mid) * a[mid];
}
}
for(int i = 1; i <= n; i++) s[i][1] = 1;
for(int i = 1; i <= n; i++) f[i][1] = w[1][i];
for(int j = 2; j <= m; j++) {
s[n + 1][j] = n;
// n -> 1 为了让 s[i + 1][j] 被求出来
for(int i = n; i >= j; i--) {
for(int k = s[i][j - 1]; k <= s[i + 1][j]; k++) {
if(f[i][j] > f[k][j - 1] + w[k + 1][i]) {
f[i][j] = f[k][j - 1] + w[k + 1][i];
s[i][j] = k;
}
}
}
}
printf("%lld", f[n][m]);
return 0;
}
杭二中白马湖p1648邮局加强版
最新推荐文章于 2020-05-28 12:54:23 发布