1 条题解
-
0
upd 2025/7/12:更新了一些错别字。 题目传送门题意
把 个数分成 个区间,使得每个数与所在区间的中位数之差的总和最小,输出这个最小值。
思路
先排序,明显的 DP:
- 定义状态: 表示前 个区域使用 种颜色的最小误差。
- 设 为区间 到 为一个颜色时的误差。我们枚举一个 ,从 到 为一个新的颜色,而 为 到 使用 种颜色,把它们相加,刚好是 ,所以我们只需要在这里求个最小值就可以了
- 状态转移:$f_{i,j}=\begin{cases} 0 & \text{ if } i=0,j=0 \\ f_{k,j-1}+color(k+1,i) & \text{ if } i>0,j>0 \end{cases}$
- 优化:这里每次 需要遍历一次 到 ,于是我们可以考虑前缀和优化。细节看代码。
代码
记得开 long long。
#include <bits/stdc++.h> using namespace std; int n, m, a[3010]; long long sum[3010], f[3010][20]; long long color(int l, int r) { int mid = (l + r) / 2; return a[mid] * (mid - l) - (sum[mid - 1] - sum[l - 1]) + sum[r] - sum[mid] - a[mid] * (r - mid); } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) scanf("%d", &a[i]); sort(a + 1, a + n + 1); for (int i = 1; i <= n; i++) sum[i] = sum[i - 1] + a[i]; memset(f, 0x3f, sizeof(f)), f[0][0] = 0; for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) for (int k = 0; k < i; k++) f[i][j] = min(f[i][j], f[k][j - 1] + color(k + 1, i)); printf("%lld", f[n][m]); return 0; }给个赞再走吧。 题目传送门
- 1
信息
- ID
- 4598
- 时间
- 1000ms
- 内存
- 128MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者