发现 m o d k \bmod k modk 不同的两个下标之间互相独立。所以考虑 dp。
设 f i , j f_{i,j} fi,j 表示选择 i i i 个长度为 ⌊ n k ⌋ \lfloor\frac{n}{k}\rfloor ⌊kn⌋ 的组, j j j 个 ⌊ n k ⌋ + 1 \lfloor \frac{n}{k}\rfloor +1 ⌊kn⌋+1 的组,得到的最小值。
有 f i , j = min ( f i − 1 , j + a 当前下标 − a 该组上一个下标 , f i , j − 1 + a 当前下标 − a 该组上一个下标 ) f_{i,j} = \min(f_{i-1,j}+a_{当前下标}-a_{该组上一个下标}, f_{i,j-1}+a_{当前下标}-a_{该组上一个下标}) fi,j=min(fi−1,j+a当前下标−a该组上一个下标,fi,j−1+a当前下标−a该组上一个下标)。
直接转移即可。时间复杂度为 O ( n k ) \mathcal O(nk) O(nk)。
#include <bits/stdc++.h>
using namespace std;
const int N = 3e5 + 10;
int a[N];
int f[5010][5010];
signed main()
{
memset(f, 0x3f, sizeof f);
int n, k;
cin >> n >> k;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + n + 1);
f[0][0] = 0;
int step = n / k;
for (int i = 0; i <= n % k; i++)
for (int j = 0; j <= (n - n % k) / step - n % k; j++)
{
int cur = i * (step + 1) + j * step;
if (i)
f[i][j] = min(f[i][j], f[i - 1][j] + a[cur] - a[cur - step]);
if (j)
f[i][j] = min(f[i][j], f[i][j - 1] + a[cur] - a[cur - step + 1]);
}
cout << f[n % k][(n - n % k) / step - n % k] << '\n';
return 0;
}