题意:给你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+斜率优化的更多相关文章

  1. HDU 3480 DP 斜率优化 Division

    把n个数分成m段,每段的值为(MAX - MIN)2,求所能划分得到的最小值. 依然是先从小到大排个序,定义状态d(j, i)表示把前i个数划分成j段,所得到的最小值,则有状态转移方程: d(j, i ...

  2. hdu 3480 Division(斜率优化DP)

    题目链接:hdu 3480 Division 题意: 给你一个有n个数的集合S,现在让你选出m个子集合,使这m个子集合并起来为S,并且每个集合的(max-min)2 之和要最小. 题解: 运用贪心的思 ...

  3. hdu 3507(DP+斜率优化)

    Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)To ...

  4. HDU 3045 DP 斜率优化 Picnic Cows

    题意:将n个数分成若干组,每组数字的个数不少于t个,要把每组的数字减小到这组最小值,求所有数字减少的最小值. 先将这n个数从小到大排个序,可以想到一组里面的数一定是排序后相邻的. 设d(i)表示前i个 ...

  5. hdu 2829 Lawrence(斜率优化DP)

    题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...

  6. HDU 3507 [Print Article]DP斜率优化

    题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...

  7. 【BZOJ-4518】征途 DP + 斜率优化

    4518: [Sdoi2016]征途 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 230  Solved: 156[Submit][Status][ ...

  8. 【BZOJ-3437】小P的牧场 DP + 斜率优化

    3437: 小P的牧场 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 705  Solved: 404[Submit][Status][Discuss ...

  9. 【BZOJ-1010】玩具装箱toy DP + 斜率优化

    1010: [HNOI2008]玩具装箱toy Time Limit: 1 Sec  Memory Limit: 162 MBSubmit: 8432  Solved: 3338[Submit][St ...

随机推荐

  1. [Swust OJ 893]--Blocks

    题目链接:http://acm.swust.edu.cn/problem/893/ Time limit(ms): 1000 Memory limit(kb): 65535   Josh loves ...

  2. (Problem 6)Sum square difference

    Hence the difference between the sum of the squares of the first ten natural numbers and the square ...

  3. Python 2.7 学习笔记 模块和包

    我们来考虑下如下几种场景: 1.编写一个python程序,如果程序比较简单,则可以把代码放到一个python文件中.但如果程序功能比较多,可能需要多个python文件来组织源代码.而这些文件之间的代码 ...

  4. jQuery 遍历ul li 添加 移除

    <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...

  5. Arduino 入门程序示例之一排 LED(2015-06-11)

    概述 最简单的一个 LED 的实验之后,自然是增加几个 LED,咱排成一排来玩吧.最后,再把一排的 LED 排成一个 8 字来玩——七段数码管. 示例程序 流水灯 第一个出场的肯定是经典的流水灯,也叫 ...

  6. win7下:MySQL-Front的下载与安装

    MySQL-Front是mysql数据库的可视化图形工具,因为它是“实时”的应用软件,它可以提供比系统内建在PHP和HTML上更为精炼的用户界面. 参考百度经验:http://jingyan.baid ...

  7. C-最长回文子串(2)

    在上一篇的文章中说到了,最长回文子串的问题,并且提到了基本的解决办法,即暴力求解法.效率O(N^3) 中心法求最长回文子串 我们知道回文字符串是以字符串中心对称的,如abba以及aba等.一个更好的办 ...

  8. OC补充

    OC 1成员变量默认初始化为0 2匿名对象:就是没有名字的对象,比如:(不建议使用) 3 [Car new]->speed = 300; [[Car new] run];(运行结果speed为0 ...

  9. 给VS自动添加注释

    找到类文件所在路径:C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\ItemTemplatesCache\CSharp\ ...

  10. 32位程序在64位系统上获取系统安装时间(要使用KEY_WOW64_64KEY标记)

    众所周知,取系统的安装时间可取注册表HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion的子项InstallDate,此值是个 ...