HDU 3480 DP+斜率优化
题意:给你n个数字,然后叫你从这些数字中选出m堆,使得每一堆的总和最小,一堆的总和就是这一堆中最大值减去最小值的平方,最后要使得所有堆加起来的总和最小。
思路:对这些数字排序之后,很容易想到DP解法,用dp[i][j]表示数字i现在在第j堆,那么转移方程就是dp[i][j] = min(dp[i][j] , dp[k][j - 1] + (a[i] - a[k + 1]) ^ 2)。因为已经排序,所以这一堆中的最大最小值其实就是a[i]和a[k + 1]。所以用DP可解。
但是注意到这实际上是需要3重循环的,而且N和M分别为10 ^ 4和5 * 10 ^ 3,所以会TLE。
其实看到转移方程后面的部分,我们就应该能想到斜率优化的方法。
假设k < l < i,我们要使得k的决策优于l,那么也就是dp[k][j - 1] + (a[i] - a[k + 1]) ^ 2 < dp[l][j - 1] + (a[i] - a[l + 1]) ^ 2 。
化简得(dp[k][j - 1] + a[k + 1] ^ 2 - (dp[l][j - 1] + a[l + 1] ^ 2)) / (2 * (a[k + 1 ] - a[l + 1])) < a[i] 。
也就是说符合上述斜率要求的k,是优于l的。
我们用g(k ,l )表示k的决策优于l。
那么我们每次更新 dp[i][j]的值的时候,只需要取出最优的决策即可,所以这一维就是O(1) .
进一步说,在第一个while 中,如果这时候队列里有两个元素,qe[l + 1] 和qe[l]。如果这时候g(qe[l + 1] , qe[l])成立,那么这时候qe[l]就不需要再计算了,因为qe[l + 1]的决策比他更优,所以我们只需要找出最优的决策,更新一次即可。
同样的,假设k < l < i 。如果g(i , l ) < g(l , k),那么此时l是可以被优化掉的。因为他不可能是最优解。这就是第二个while的作用。
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Max 2505
#define FI first
#define SE second
#define ll long long
#define PI acos(-1.0)
#define inf 0x3fffffff
#define LL(x) ( x << 1 )
#define bug puts("here")
#define PII pair<int,int>
#define RR(x) ( x << 1 | 1 )
#define mp(a,b) make_pair(a,b)
#define mem(a,b) memset(a,b,sizeof(a))
#define REP(i,s,t) for( int i = ( s ) ; i <= ( t ) ; ++ i ) using namespace std; #define N 11111
#define M 5555
int dp[N][M] ;
int a[N] ; int getU(int j ,int k ,int z){
return dp[k][j - 1] + a[k + 1] * a[k + 1] - (dp[z][j - 1] + a[z + 1] * a[z + 1]) ;
}
int getD(int k , int z){
return 2 * (a[k + 1] - a[z + 1]) ;
} int getDP(int i , int j ,int k){
return dp[k][j - 1] + (a[i] - a[k + 1]) * (a[i] - a[k + 1]) ;
}
int qe[N * 10] ;
void solve(){
int n , m ;
cin >> n >> m ;
for (int i = 1 ; i <= n ; i ++ )cin >> a[i] ;
sort(a + 1 , a + n + 1 ) ; for (int i = 0 ; i <= n ; i ++ ){
for (int j = 0 ; j <= m ; j ++ )
dp[i][j] = inf ;
dp[i][1] = (a[i] - a[1]) * (a[i] - a[1]) ;
}
dp[0][0] = 0 ;
for (int j = 1 ; j <= m ; j ++ ){
int l = 0 , r = 0 ;
qe[r ++ ] = 0 ;
for (int i = 1 ; i <= n ; i ++ ){
while(l + 1 < r && getU(j , qe[l + 1] , qe[l]) <= a[i] * getD(qe[l + 1] ,qe[l]))l ++ ;
dp[i][j] = getDP(i , j , qe[l]) ;
while(l + 1 < r && getU(j , i , qe[r - 1]) * getD(qe[r - 1] , qe[r - 2]) <=
getU(j , qe[r - 1] , qe[r - 2]) * getD(i , qe[r - 1]))r -- ;
qe[r ++ ] = i ;
}
}
cout << dp[n][m] << endl;
}
int main() {
int ca = 0 ;
int t ; cin >> t ; while(t -- ){
printf("Case %d: ",++ca) ;
solve() ;
}
return 0 ;
}
HDU 3480 DP+斜率优化的更多相关文章
- HDU 3480 DP 斜率优化 Division
把n个数分成m段,每段的值为(MAX - MIN)2,求所能划分得到的最小值. 依然是先从小到大排个序,定义状态d(j, i)表示把前i个数划分成j段,所得到的最小值,则有状态转移方程: d(j, i ...
- hdu 3480 Division(斜率优化DP)
题目链接:hdu 3480 Division 题意: 给你一个有n个数的集合S,现在让你选出m个子集合,使这m个子集合并起来为S,并且每个集合的(max-min)2 之和要最小. 题解: 运用贪心的思 ...
- hdu 3507(DP+斜率优化)
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- HDU 3045 DP 斜率优化 Picnic Cows
题意:将n个数分成若干组,每组数字的个数不少于t个,要把每组的数字减小到这组最小值,求所有数字减少的最小值. 先将这n个数从小到大排个序,可以想到一组里面的数一定是排序后相邻的. 设d(i)表示前i个 ...
- hdu 2829 Lawrence(斜率优化DP)
题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...
- HDU 3507 [Print Article]DP斜率优化
题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...
- 【BZOJ-4518】征途 DP + 斜率优化
4518: [Sdoi2016]征途 Time Limit: 10 Sec Memory Limit: 256 MBSubmit: 230 Solved: 156[Submit][Status][ ...
- 【BZOJ-3437】小P的牧场 DP + 斜率优化
3437: 小P的牧场 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 705 Solved: 404[Submit][Status][Discuss ...
- 【BZOJ-1010】玩具装箱toy DP + 斜率优化
1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec Memory Limit: 162 MBSubmit: 8432 Solved: 3338[Submit][St ...
随机推荐
- [Swust OJ 893]--Blocks
题目链接:http://acm.swust.edu.cn/problem/893/ Time limit(ms): 1000 Memory limit(kb): 65535 Josh loves ...
- (Problem 6)Sum square difference
Hence the difference between the sum of the squares of the first ten natural numbers and the square ...
- Python 2.7 学习笔记 模块和包
我们来考虑下如下几种场景: 1.编写一个python程序,如果程序比较简单,则可以把代码放到一个python文件中.但如果程序功能比较多,可能需要多个python文件来组织源代码.而这些文件之间的代码 ...
- jQuery 遍历ul li 添加 移除
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- Arduino 入门程序示例之一排 LED(2015-06-11)
概述 最简单的一个 LED 的实验之后,自然是增加几个 LED,咱排成一排来玩吧.最后,再把一排的 LED 排成一个 8 字来玩——七段数码管. 示例程序 流水灯 第一个出场的肯定是经典的流水灯,也叫 ...
- win7下:MySQL-Front的下载与安装
MySQL-Front是mysql数据库的可视化图形工具,因为它是“实时”的应用软件,它可以提供比系统内建在PHP和HTML上更为精炼的用户界面. 参考百度经验:http://jingyan.baid ...
- C-最长回文子串(2)
在上一篇的文章中说到了,最长回文子串的问题,并且提到了基本的解决办法,即暴力求解法.效率O(N^3) 中心法求最长回文子串 我们知道回文字符串是以字符串中心对称的,如abba以及aba等.一个更好的办 ...
- OC补充
OC 1成员变量默认初始化为0 2匿名对象:就是没有名字的对象,比如:(不建议使用) 3 [Car new]->speed = 300; [[Car new] run];(运行结果speed为0 ...
- 给VS自动添加注释
找到类文件所在路径:C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\ItemTemplatesCache\CSharp\ ...
- 32位程序在64位系统上获取系统安装时间(要使用KEY_WOW64_64KEY标记)
众所周知,取系统的安装时间可取注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion的子项InstallDate,此值是个 ...