题目描述

现在有一个长度为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. IPsec_VPN实现技术【转载】

    GRE Tunnel GRE Tunnel(General Routing Encapsulation 通用路由封装)是一种非常简单的VPN(Virtual Private Network 虚拟专用网 ...

  2. 转:Java IO流学习总结

    Java流操作有关的类或接口: Java流类图结构: 流的概念和作用 流是一组有顺序的,有起点和终点的字节集合,是对数据传输的总称或抽象.即数据在两设备间的传输称为流,流的本质是数据传输,根据数据传输 ...

  3. 如何使用Git和码云Git@OSC

    1.Git简介 关于Git是什么,阅读博客Git简介 2.Git 基础 Git命令很多,常用命令如下图 Workspace:工作区 Index/Stage :暂存区 Local Repository: ...

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

    1. 本周学习总结 以你喜欢的方式(思维导图或其他)归纳总结集合相关内容. 参考资料: XMind 2. 书面作业 1.ArrayList代码分析 1.1 解释ArrayList的contains源代 ...

  5. 201521123081《java程序设计》 第14周学习总结

    1. PTA反馈问卷 2. 雨课堂反馈问卷 本次作业参考文件 数据库PPT MySql操作视频与数据库相关jar文件请参考QQ群文件. 0. 本周课程设计发布 Java课程设计 1. 本周学习总结 1 ...

  6. 《JAVA程序设计》第11周学习总结

    1. 本章学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多线程相关内容. synchronized方法/代码块 wait().notify()用法,生产者消费者例子 lock.condit ...

  7. 201521123011《Java程序设计》第14周学习总结

    1. 本周学习总结 1.1 以你喜欢的方式(思维导图或其他)归纳总结多数据库相关内容. MySql数据库简单操作 1.启动与退出(quit或exit ) 操作 显示所有数据库: show databa ...

  8. 域名解析>>"记录类型" 说明

    (1)A (Address) 记录是用来指定主机名(或域名)对应的IP地址记录. 说明:用户可以将该域名下的网站服务器指向到自己的web server上.同时也可以设置自己域名的二级域名. (2)MX ...

  9. Servlet第五篇【介绍会话技术、Cookie的API、详解、应用】

    什么是会话技术 基本概念: 指用户开一个浏览器,访问一个网站,只要不关闭该浏览器,不管该用户点击多少个超链接,访问多少资源,直到用户关闭浏览器,整个这个过程我们称为一次会话. 为什么我们要使用会话技术 ...

  10. PyTorch教程之Neural Networks

    我们可以通过torch.nn package构建神经网络. 现在我们已经了解了autograd,nn基于autograd来定义模型并对他们有所区分. 一个 nn.Module模块由如下部分构成:若干层 ...