我的第一道斜率优化。

就这道题而言,写出原始的方程:

  dp[i] = min{ dp[j] + (sum[i]-sum[j])+ 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 斜率优化的更多相关文章

  1. Print Article HDU - 3507 -斜率优化DP

    思路 : 1,用一个单调队列来维护解集. 2,假设队列中从头到尾已经有元素a b c.那么当d要入队的时候,我们维护队列的下凸性质, 即如果g[d,c]<g[c,b],那么就将c点删除.直到找到 ...

  2. HDU 3507 斜率优化dp

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

  3. HDU 3507斜率优化dp

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

  4. HDU 3507 斜率优化 DP Print Article

    在kuangbin巨巨博客上学的. #include <iostream> #include <cstdio> #include <cstring> #includ ...

  5. hdu 3507 斜率dp

    不好理解,先多做几个再看 此题是很基础的斜率DP的入门题. 题意很清楚,就是输出序列a[n],每连续输出的费用是连续输出的数字和的平方加上常数M 让我们求这个费用的最小值. 设dp[i]表示输出前i个 ...

  6. hdu 3669(斜率优化DP)

    Cross the Wall Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others) ...

  7. HDU 4258 斜率优化dp

    Covered Walkway Time Limit: 30000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Othe ...

  8. HDU 2829 斜率优化DP Lawrence

    题意:n个数之间放m个障碍,分隔成m+1段.对于每段两两数相乘再求和,然后把这m+1个值加起来,让这个值最小. 设: d(i, j)表示前i个数之间放j个炸弹能得到的最小值 sum(i)为前缀和,co ...

  9. hdu 3045 斜率优化DP

    思路:dp[i]=dp[j]+sum[i]-sum[j]-(i-j)*num[j+1]; 然后就是比较斜率. 注意的时这里j+t<=i: #include<iostream> #in ...

随机推荐

  1. 2018中国科大自主测试-B卷部分试题

    数学部分 z = e^{\frac{2i\pi}{3}}, 求z^{2018}. \sin(2x) = \frac 35, 求\frac{\tan(x+15^{\circ})}{\tan(x-15^{ ...

  2. 深入理解C指针----学习笔记

      深入理解C指针     第1章 认识指针   理解指针的关键在于理解C程序如何管理内存,指针包含的就是内存地址.     1.1 指针和内存   C程序在编译后,以三种方式使用内存: 1. 静态. ...

  3. 二. Jmeter--参数化

    1. 新建一个txt文件,输入些数据, 一行有四个数据,用逗号分隔. 保存的时候Encoding选择Unicode 2.添加一个Thread Group, 然后添加一个CSV Data Set Con ...

  4. 选择问题(选择数组中第K小的数)

    由排序问题可以引申出选择问题,选择问题就是选择并返回数组中第k小的数,如果把数组全部排好序,在返回第k小的数,也能正确返回,但是这无疑做了很多无用功,由上篇博客中提到的快速排序,稍稍修改下就可以以较小 ...

  5. Linux进程的创建函数fork()及其fork内核实现解析【转】

    转自:http://www.cnblogs.com/zengyiwen/p/5755193.html 进程的创建之fork() Linux系统下,进程可以调用fork函数来创建新的进程.调用进程为父进 ...

  6. python基础===对字符串进行左右中对齐

    例如,有一个字典如下: >>> dic = { "name": "botoo", "url": "http:// ...

  7. juery中监听input的变化事件

    $('#searchValue').bind('input propertychange', function() { searchFundList(); });

  8. MySQL-索引工作原理及使用注意事项

    1.为什么需要索引(Why is it needed)? 当数据保存在磁盘类存储介质上时,它是作为数据块存放.这些数据块是被当作一个整体来访问的,这样可以保证操作的原子性.硬盘数据块存储结构类似于链表 ...

  9. URAL题解一

    URAL题解一 URAL 1002 题目描述:一种记住手机号的方法就是将字母与数字对应,如图.这样就可以只记住一些单词,而不用记住数字.给出一个数字串和n个单词,用最少的单词数来代替数字串,输出对应的 ...

  10. Python连接Access数据库

    前言 今天想要用Python访问Access数据库,折腾了半天,特记录一下 背景 最近想将一些文件记录下来,存入数据库,为此拿LabVIEW写了一个版本,记录环境配置为: LabVIWE:2015 A ...