题目描述

现在有一个长度为n的数组A,另外还有一个整数k。数组下标从1开始。

现在你需要把数组的顺序重新排列一下使得下面这个的式子的值尽可能小。

∑|A[i]−A[i+k]|

特别的,你也可以不对数组进行重新排列。

Input

单组测试数据。

第一行包含两个整数n,k (2≤n≤3*10^5, 1≤k≤min(5000,n-1))。

第二行包含n个整数 A[1],A[2],...,A[n] (-10^9≤A[i]≤10^9)。

Output

输出答案占一行。

Input示例

3 2

1 2 4

Output示例

1


题解

这道题相当于把所有数分成了互不关联的k组,由于n不一定是k的倍数,其中一些组有 n / k + 1个元素,另一些有 n / k 个元素。

在每一组中,为了使“相邻元素的差的绝对值之和”最小,将元素从小到大排序,则这一组的“相邻元素的差的绝对值之和”就是最大元素-最小元素。那么只要使每一组的最大值-最小值最小就好了。

很容易想到把整个数组排好序后,直接取前n/k + 1组为第一组,取下面n/k + 1组为第二组……在n是k的倍数时这很好,可一个问题是:有些组有n/k个元素,有些有n/k+1个元素,令哪些组为前者,哪些为后者呢?这会影响最终的答案。

发现两种“组”的数目是固定的,并且都小于等于5000,那么我们结合dp:

dp[i][j]表示n/k + 1个元素的组已经选了i个,n/k个元素的组已经选了j个,能得到的最小分数。

dp[i][j] 可以从 dp[i - 1][j] 和 dp[i][j - 1]两个转移。

设排序后的序列为a[i], p1表示dp[i - 1][j]在排序后的序列中一共用完了前多少个元素,p2表示dp[i][j - 1]在排序后的序列中一共用完了前多少个元素。

那么可以写出状态转移方程:

dp[i][j] = min(dp[i - 1][j] + a[p1 + (n/k + 1)] - a[p1 + k], dp[i][j - 1] + a[p2 + n/k] - a[p2])

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
#define INF 0x3f3f3f3f
#define space putchar(' ')
#define enter putchar('\n')
template <class T>
bool read(T &x){
char c;
bool minus = ;
while(c = getchar(), c < '' || c > '')
if(c == '-') minus = ;
else if(c == EOF) return ;
x = c - '';
while(c = getchar(), c >= '' && c <= '')
x = x * + c - '';
if(minus) x = -x;
return ;
}
template <class T>
void write(T x){
if(x < ) putchar('-'), x = -x;
if(x >= ) write(x / );
putchar('' + x % );
} const int N = , M = ;
int n, k, l1, l2, t1, t2, a[N], dp[M][M]; int main(){ read(n), read(k);
for(int i = ; i <= n; i++)
read(a[i]);
sort(a + , a + n + );
l1 = n/k + , l2 = n/k;
t1 = n % k, t2 = k - t1;
for(int i = , p = ; i <= t1; i++)
dp[i][] = dp[i - ][] + a[p + l1] - a[p + ], p += l1;
for(int j = , p = ; j <= t2; j++)
dp[][j] = dp[][j - ] + a[p + l2] - a[p + ], p += l2;
for(int i = , p1, p2; i <= t1; i++)
for(int j = ; j <= t2; j++){
p1 = (i - ) * l1 + j * l2;
p2 = i * l1 + (j - ) * l2;
dp[i][j] = min(dp[i - ][j] + a[p1 + l1] - a[p1 + ],
dp[i][j - ] + a[p2 + l2] - a[p2 + ]);
}
write(dp[t1][t2]), enter; return ;
}

51nod 1510 最小化序列 | DP 贪心的更多相关文章

  1. 【51Nod】1510 最小化序列 贪心+动态规划

    [题目]1510 最小化序列 [题意]给定长度为n的数组A和数字k,要求重排列数组从而最小化: \[ans=\sum_{i=1}^{n-k}|A_i-A_{i+k}|\] 输出最小的ans,\(n \ ...

  2. UVA 714 Copying Books 最大值最小化问题 (贪心 + 二分)

      Copying Books  Before the invention of book-printing, it was very hard to make a copy of a book. A ...

  3. 【BZOJ-1046】上升序列 DP + 贪心

    1046: [HAOI2007]上升序列 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 3723  Solved: 1271[Submit][Stat ...

  4. luogu P5470 [NOI2019]序列 dp 贪心 费用流 模拟费用流

    LINK:序列 考虑前20分 容易想到爆搜. 考虑dp 容易设\(f_{i,j,k,l}\)表示前i个位置 选了j对 且此时A选择了k个 B选择了l个的最大值.期望得分28. code //#incl ...

  5. 最大值最小化(DP)

    题目来源:网易有道2013年校园招聘面试一面试题 题目描述: 在印刷术发明之前,复制一本书是一个很困难的工作,工作量很大,而且需要大家的积极配合来抄写一本书,团队合作能力很重要.当时都是通过招募抄写员 ...

  6. 51nod 1065 最小正子段和 (贪心)

    题目:传送门. 题意:中文题. 题解:求前缀和,并且标记每个数的下标,按照前缀和大小进行从小到大排序.随后进行遍历,如果满足下标data[i-1].id<data[i].id&& ...

  7. [BZOJ1046][HAOI2007]上升序列 DP+贪心

    题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=1046 我们先求出对于每一个数字作为开头的LCS的长度f[i],最长的f[i]为mxlen. ...

  8. UVa 714 Copying books 贪心+二分 最大值最小化

    题目大意: 要抄N本书,编号为1,2,3...N, 每本书有1<=x<=10000000页, 把这些书分配给K个抄写员,要求分配给某个抄写员的那些书的编号必须是连续的.每个抄写员的速度是相 ...

  9. POJ3273-Monthly Expense (最小化最大值)

    题目链接:cid=80117#problem/E">click here~~ [题目大意] 农夫JF在n天中每天的花费,要求把这n天分作m组.每组的天数必定是连续的.要求分得各组的花费 ...

随机推荐

  1. idea 给maven项目添加依赖(二)

    这里接着上一篇来 我们观察目录发现有两个pom.xml(project object module) 项目是里面的,所以外面的先不管它. 点击里面的pom.xml 1.在<url>节点下面 ...

  2. 【★】RSA-什么是不对称加密算法?

    不对称加密算法RSA浅析 本文主要介绍不对称加密算法中最精炼的RSA算法.我们先说结论,也就是RSA算法怎么算,然后再讲为什么. 随便选取两个不同的大素数p和q,N=p*q,r=(p-1)*(q-1) ...

  3. 使用JSR-303进行校验 @Valid

    一.在SringMVC中使用 使用注解 1.准备校验时使用的JAR validation-api-1.0.0.GA.jar:JDK的接口: hibernate-validator-4.2.0.Fina ...

  4. java简单数据类型转化

    java简单数据类型,有低级到高级为:(byte,short,char)→int→long→float→double (boolean不参与运算转化) 转化可以分为 低级到高级的自动转化 高级到低级的 ...

  5. 团队作业4——第一次项目冲刺(Alpha版本)2017.4.26

    2017.04.26 天气热. 时间:上午 9:35 ---10:10分 地点:陆大304实验室 会议内容:今天将昨天的的一些问题进行了讨论,以及针对助教提出的问题进行了分析,是因为我们昨天经过讨论后 ...

  6. 201521123069 《Java程序设计》 第7周学习总结

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind List列表:元素以线性方式存放,允许有重复的对象. Set集:集合中的对象不按特定的方式排序,并且 ...

  7. 201521123003《Java程序设计》第4周学习总结

    1. 本章学习总结 你对于本章知识的学习总结 1.1 尝试使用思维导图总结有关继承的知识点. 参考资料: 百度脑图 XMind 1.2 使用常规方法总结其他上课内容. (1)了解了类型转换(cast) ...

  8. 201521123086《java程序设计》第四周

    本章学习总结 尝试使用思维导图总结有关继承的知识点 1.2 使用常规方法总结其他上课内容. 为了不必要写重复的代码,可以运用继承,用关键字extends来定义一个类,被继承的类叫做父类,继承的类叫做子 ...

  9. 201521123122 Java 第二周学习总结

    1. 本周学习总结 1.进一步了解了对码云的使用,学会了将本地代码上传到码云以及将码云上的代码克隆到eclipse上. 2.感觉本章学的基本语法和c的基本上差不多啊 3.string的对象创建后无法修 ...

  10. Java程序设计——学生基本信息管理系统

    1.团队课程设计博客链接 http://www.cnblogs.com/handsome321/p/7067121.html 2.个人负责模块说明 本组课题:学生信息管理系统 本人任务:插入.删除学生 ...