CodeForces 572D Minimization(DP)
题意翻译
给定数组AAA 和值kkk ,你可以重排AAA 中的元素,使得∑i=1n−k∣Ai−Ai+k∣\displaystyle\sum_{i=1}^{n-k} |A_i-A_{i+k}|i=1∑n−k∣Ai−Ai+k∣ 最小。输出最小值。
题目描述
You've got array A A A , consisting of n n n integers and a positive integer k k k . Array A A A is indexed by integers from 1 1 1 to n n n .
You need to permute the array elements so that value
became minimal possible. In particular, it is allowed not to change order of elements at all.
输入输出格式
输入格式:
The first line contains two integers n,k n,k n,k ( 2<=n<=3⋅105 2<=n<=3·10^{5} 2<=n<=3⋅105 , 1<=k<=min(5000,n−1) 1<=k<=min(5000,n-1) 1<=k<=min(5000,n−1) ).
The second line contains n n n integers A[1],A[2],...,A[n] A[1],A[2],...,A[n] A[1],A[2],...,A[n] ( −109<=A[i]<=109 -10^{9}<=A[i]<=10^{9} −109<=A[i]<=109 ), separate by spaces — elements of the array A A A .
输出格式:
Print the minimum possible value of the sum described in the statement.
输入输出样例
输入样例#1: 复制
3 2
1 2 4
输出样例#1: 复制
1
输入样例#2: 复制
5 2
3 -5 3 -5 3
输出样例#2: 复制
0
输入样例#3: 复制
6 3
4 3 4 3 2 5
输出样例#3: 复制
3
说明
In the first test one of the optimal permutations is $ 1 4 2 $ .
In the second test the initial order is optimal.
In the third test one of the optimal permutations is $ 2 3 4 4 3 5 $ .
题解:首先显然如果把i,i+k,i+2×k等排列起来,这将是一条链,而且会有k条链。
链长可能有两种情况:n/k,n/k+1
显然同一条链中如果数字固定,单调的话链的贡献最小
显然如果单调的话,取连续的几个贡献最小
所以我们现将全部数字放到同一条链里,接着将这条长链断成k条长度为n/k,n/k+1的链,此时贡献需要减掉两条链之间的差值
于是问题转化成了求减掉差值的和的最大值
令i表示长边数量,j表示短边的数量
dp[i][j]=max(dp[i][j-1]+det1,dp[i-1][j]+det2)
因为只有两种边长,所以分割点所在的位置可以直接根据i和j推出
总贡献减去dp[cnt1][cnt2]即为答案
代码如下:
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define int long long using namespace std; int n,k,a[300030]; int dp[5010][5010]; int ans; signed main() { scanf("%lld%lld",&n,&k); int cnt1=n%k; int cnt2=k-cnt1; int len1=n/k+1; int len2=n/k; for(int i=1;i<=n;i++) { scanf("%lld",&a[i]); } sort(a+1,a+n+1); for(int i=2;i<=n;i++) { ans+=a[i]-a[i-1]; } for(int i=2;i<=cnt1;i++) { dp[i][0]=dp[i-1][0]+a[i*len1-len1+1]-a[i*len1-len1]; } for(int i=2;i<=cnt2;i++) { dp[0][i]=dp[0][i-1]+a[i*len2-len2+1]-a[i*len2-len2]; } for(int i=1;i<=cnt1;i++) { for(int j=1;j<=cnt2;j++) { dp[i][j]=max(dp[i][j-1]+a[i*len1+j*len2-len2+1]-a[i*len1+j*len2-len2],dp[i-1][j]+a[i*len1+j*len2-len1+1]-a[i*len1+j*len2-len1]); } } printf("%lld",ans-dp[cnt1][cnt2]); }