发现 mod k\bmod kmodk 不同的两个下标之间互相独立。所以考虑 dp。
设 fi,jf_{i,j}fi,j 表示选择 iii 个长度为 ⌊nk⌋\lfloor\frac{n}{k}\rfloor⌊kn⌋ 的组,jjj 个 ⌊nk⌋+1\lfloor \frac{n}{k}\rfloor +1⌊kn⌋+1 的组,得到的最小值。
有 fi,j=min(fi−1,j+a当前下标−a该组上一个下标,fi,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(nk)\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;
}
文章描述了一种使用动态规划解决的问题,目标是找到在给定数组中,选择不同长度的子数组(长度为n/k和n/k+1),使得这些子数组元素之和的差值最小。通过状态转移方程f[i,j]=min(f[i-1,j]+a[cur]-a[cur-step],f[i,j-1]+a[cur]-a[cur+step]),计算出最小差值。时间复杂度为O(nk)。
697






