hdu 3507 斜率优化
我的第一道斜率优化。
就这道题而言,写出原始的方程:
dp[i] = min{ dp[j] + (sum[i]-sum[j])2 + M | j in [0,i) }
O(n^2)的复杂度肯定超时,要么优化转移,要么重写方程。
斜率优化的思想就是减少不必要的枚举(即不枚举肯定不会成为决策点的j)。
我们考虑两个位置p<q<i
“选择q比选择p优” 当且仅当 dp[q]+(sum[i]-sum[q])2+M < dp[p]+(sum[i]-sum[p])2+M
化简右边即:
[ (dp[q]+sum2[q])-(dp[p]+sum2[p]) ] / ( sum[q]-sum[p] ) < sum[i]*2
该式可以看成两个点连线的斜率:( sum[q], dp[q]+sum2[q] ) 与 ( sum[p], dp[p]+sum2[p] ) 两点。
文字语言就是:“将每个决策位置看成一个二维坐标系下的点,对于两个决策点,后者比前者优 当且仅当 两点连线的斜率小于sum[i]*2”
这样怎么减少不必要的枚举呢?
可以发现,所有决策点一定是单调不下降的(题中可能出现权值为0,此时有可能出现斜率为正无穷,若M=0,还有可能出现重点,所以计算斜率不要用除法)

上面的B点一定是不会成为最优决策点的,反证法:
如果B成为最优决策点,那么
2*sum[i]>kab 且 2*sum[i]<kbc
而显然kab > kbc ,这样就推出了2*sum[i]>kab >kbc >2*sum[i],矛盾。
故B不可能成为最优决策点,同理,D也不行,删掉这些点后,我们剩下的图形就是一个下凸的图形了:

我们维护这样一个下凸的图形到队列中:
当要查找i位置的最优决策点时,一直删除队首的点,直到队中的第一条直线的斜率大于2*sum[i]或队中只有一个点,此时队首元素就是最优决策点。
计算完i位置后,要将i位置对应的点加入到队列中,此时会删除一些对尾的点,以保持队中点的下凸性(注意处理重合的点)。
这样,我们就利用斜率优化掉了很多不必要的枚举,将时间复杂度从O(n^2)降到了O(n)。
#include <cstdio>
#define ln(A,B) ((B)-(A))
#define maxn 500010 typedef long long lng; struct Vector {
lng x, y;
int id;
Vector(){}
Vector( lng x, lng y, int id ) : x(x), y(y), id(id) {}
Vector operator-( const Vector & b ) const { return Vector(x-b.x,y-b.y,); }
lng operator&( const Vector & b ) const {
return x*b.y-y*b.x;
}
};
typedef Vector Point; int n, m;
int cost[maxn];
lng sum[maxn];
lng dp[maxn]; int beg, end;
Point qu[maxn]; int main() {
while( ) {
if( scanf( "%d%d", &n, &m )!= ) return ; sum[] = ;
for( int i=; i<=n; i++ ) {
scanf( "%d", cost+i );
sum[i] = sum[i-]+cost[i];
} dp[] = ;
qu[beg=end=] = Point( , , ); for( int i=; i<=n; i++ ) {
while( end>beg && qu[beg+].y-qu[beg].y<=(qu[beg+].x-qu[beg].x)**sum[i] )
beg++;
int j = qu[beg].id;
dp[i] = dp[j]+(sum[i]-sum[j])*(sum[i]-sum[j])+m;
Point npt = Point( sum[i], dp[i]+sum[i]*sum[i], i );
while( end>beg && (ln(qu[end-],qu[end])&ln(qu[end-],npt))<= )
end--;
qu[++end] = npt;
}
printf( "%lld\n", dp[n] );
}
}
hdu 3507 斜率优化的更多相关文章
- Print Article HDU - 3507 -斜率优化DP
思路 : 1,用一个单调队列来维护解集. 2,假设队列中从头到尾已经有元素a b c.那么当d要入队的时候,我们维护队列的下凸性质, 即如果g[d,c]<g[c,b],那么就将c点删除.直到找到 ...
- HDU 3507 斜率优化dp
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- HDU 3507斜率优化dp
Print Article Time Limit: 9000/3000 MS (Java/Others) Memory Limit: 131072/65536 K (Java/Others)To ...
- HDU 3507 斜率优化 DP Print Article
在kuangbin巨巨博客上学的. #include <iostream> #include <cstdio> #include <cstring> #includ ...
- hdu 3507 斜率dp
不好理解,先多做几个再看 此题是很基础的斜率DP的入门题. 题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M 让我们求这个费用的最小值. 设dp[i]表示输出前i个 ...
- hdu 3669(斜率优化DP)
Cross the Wall Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 327680/327680 K (Java/Others) ...
- HDU 4258 斜率优化dp
Covered Walkway Time Limit: 30000/10000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Othe ...
- HDU 2829 斜率优化DP Lawrence
题意:n个数之间放m个障碍,分隔成m+1段.对于每段两两数相乘再求和,然后把这m+1个值加起来,让这个值最小. 设: d(i, j)表示前i个数之间放j个炸弹能得到的最小值 sum(i)为前缀和,co ...
- hdu 3045 斜率优化DP
思路:dp[i]=dp[j]+sum[i]-sum[j]-(i-j)*num[j+1]; 然后就是比较斜率. 注意的时这里j+t<=i: #include<iostream> #in ...
随机推荐
- let块级作用域
let是es6中新加的作用域,即块级作用域. var申明的变量要么全局,要么函数级,而let允许把变量的作用域限制在块级域中,这里的块级可以是()内,或{}内. 示例: code_1: "u ...
- java 1.8 新特性 stream
并发提升 java 中Stream类似于hadoop中的数据分析的思路,只不过hadoop大,用的是多台机算机的计算生态,而java stream使用的单台计算机中的多cpu分析一块数据的过程.通过 ...
- 005zabbix3.0报错记录
一.问题描述 在zabbix_server添加变量时,出现了以下的报错,
- [写出来才有价值系列:node.js]node.js 02-,learnyounode
安装learnyounode: npm install g learnyounode 官方说直接 但是我发现不行,很慢几乎就是死在那里了 还好有淘宝的东西给我们用https://npm.taobao. ...
- spring-mybatis.xml配置
1.自动扫描 <context:component-scan base-package="com.javen" /> 2.引入配置文件 <bean id=&quo ...
- C语言实现int转换string
#include <stdio.h> #include <stdlib.h> #include <string.h> int string2int(const ch ...
- 如何删除git远程分支(转)
1,在开发过程中,大家在远程创建了许多分支,有些是无用的,该如何删除呢,可以参考下面的方法. 如果不再需要某个远程分支了,比如搞定了某个特性并把它合并进了远程的 master 分支(或任何其他存放 稳 ...
- linux中getmntent setmntent endmntent 用法例子
mntent 结构是在 <mntent.h> 中定义,如下: struct mntent { char *mnt ...
- linux下c图形化编程之gtk+2.0简单学习
在linux下想做一个图形化的界面,然后自己选择使用gtk+2.0来进行编辑,我的电脑已经安装过gtk+2.0了,所以就在网上找了一个安装方法,结果未测试,大家有安装问题可以说下,一起探讨下. 1.安 ...
- Windows内核分析——内核调试机制的实现(NtCreateDebugObject、DbgkpPostFakeProcessCreateMessages、DbgkpPostFakeThreadMessages分析)
本文主要分析内核中与调试相关的几个内核函数. 首先是NtCreateDebugObject函数,用于创建一个内核调试对象,分析程序可知,其实只是一层对ObCreateObject的封装,并初始化一些结 ...