Codeforces Round #317 [AimFund Thanks-Round] (Div. 2) D. Minimization(dp)
2016-02-04 18:34
423 查看
题意:
给定一个N≤3×105的序列,给定一个1≤K≤min(5000,n−1)
通过重排原序列,求最小的∑n−ki=1|Ai−Ai+k|
分析:
观察这个式子,里面其实就是|Aj−Ai|,j≡i mod k
那么我们把原序列按照模k的余数分类,总共有k个子序列,0∼k−1
发现其中有n%k个子序列的长度为n/k+1,n−n%k个长度为n/k
假设其实一个序列是b1,b2,...,bm这样排列值最优的
它的贡献就是Ei=|b2−b1|+|b3−b2|+|b4−b3|+⋯+|bm−bm−1|
让这样的贡献最小,显然我们应该让这个序列的相邻数的差距最近
那么这样的序列一定是原序列有序排序后,其中连续的一部分
这样之后b1≤b2≤⋯≤bm
显然Ei=b2−b1+b3−b2+b4−b3+⋯+bm−bm−1=bm−b1
那么原问题就转化为有序序列中选取n%k个长连续子序列,n−n%k个短连续子序列的最优解
dp[large][small]:=选取large个长连续子序列,small个短连续子序列的最优解
转移就枚举选取的这个是长还是短就可以了
时间复杂度为O(nlogn+k2)
注意细节。
代码:
给定一个N≤3×105的序列,给定一个1≤K≤min(5000,n−1)
通过重排原序列,求最小的∑n−ki=1|Ai−Ai+k|
分析:
观察这个式子,里面其实就是|Aj−Ai|,j≡i mod k
那么我们把原序列按照模k的余数分类,总共有k个子序列,0∼k−1
发现其中有n%k个子序列的长度为n/k+1,n−n%k个长度为n/k
假设其实一个序列是b1,b2,...,bm这样排列值最优的
它的贡献就是Ei=|b2−b1|+|b3−b2|+|b4−b3|+⋯+|bm−bm−1|
让这样的贡献最小,显然我们应该让这个序列的相邻数的差距最近
那么这样的序列一定是原序列有序排序后,其中连续的一部分
这样之后b1≤b2≤⋯≤bm
显然Ei=b2−b1+b3−b2+b4−b3+⋯+bm−bm−1=bm−b1
那么原问题就转化为有序序列中选取n%k个长连续子序列,n−n%k个短连续子序列的最优解
dp[large][small]:=选取large个长连续子序列,small个短连续子序列的最优解
转移就枚举选取的这个是长还是短就可以了
时间复杂度为O(nlogn+k2)
注意细节。
代码:
// // Created by TaoSama on 2016-02-04 // Copyright (c) 2016 TaoSama. All rights reserved. // #pragma comment(linker, "/STACK:1024000000,1024000000") #include <algorithm> #include <cctype> #include <cmath> #include <cstdio> #include <cstdlib> #include <cstring> #include <iomanip> #include <iostream> #include <map> #include <queue> #include <string> #include <set> #include <vector> using namespace std; #define pr(x) cout << #x << " = " << x << " " #define prln(x) cout << #x << " = " << x << endl const int N = 3e5 + 10, INF = 0x3f3f3f3f, MOD = 1e9 + 7; typedef long long LL; int n, k, a ; LL f[5005][5005]; int main() { #ifdef LOCAL freopen("C:\\Users\\TaoSama\\Desktop\\in.txt", "r", stdin); // freopen("C:\\Users\\TaoSama\\Desktop\\out.txt","w",stdout); #endif ios_base::sync_with_stdio(0); while(scanf("%d%d", &n, &k) == 2) { for(int i = 1; i <= n; ++i) scanf("%d", a + i); sort(a + 1, a + 1 + n); int len = n / k, large = n % k, small = k - large; memset(f, 0x3f, sizeof f); f[0][0] = 0; for(int i = 0; i <= large; ++i) { for(int j = 0; j <= small; ++j) { int st = i * (len + 1) + j * len + 1; if(i < large) { int largeCost = a[st + len] - a[st]; f[i + 1][j] = min(f[i + 1][j], f[i][j] + largeCost); } if(j < small) { int smallCost = a[st + len - 1] - a[st]; f[i][j + 1] = min(f[i][j + 1], f[i][j] + smallCost); } } } printf("%I64d\n", f[large][small]); } return 0; }
相关文章推荐
- 基于Android中dp和px之间进行转换的实现代码
- Android中dip、dp、sp、pt和px的区别详解
- LFC1.0.0 版本发布
- Android px、dp、sp之间相互转换
- HP data protector软件学习1--基本角色与基本工作流程
- HP data protector软件学习2--软件组成与界面介绍
- android中像素单位dp、px、pt、sp的比较
- Android对px和dip进行尺寸转换的方法
- Android根据分辨率进行单位转换-(dp,sp转像素px)
- android 尺寸 dp,sp,px,dip,pt详解
- DP问题各种模型的状态转移方程
- POJ-1695-Magazine Delivery-dp
- nyoj-1216-整理图书-dp
- TYVJ1193 括号序列解题报告
- 对DP的一点感想
- TYVJ上一些DP的解题报告
- soj1005. Roll Playing Games
- 01背包问题
- LeetCode之Maximum Product Subarray
- DP Flow