HDU 2829 [Lawrence] DP斜率优化
解题思路
首先肯定是考虑如何快速求出一段铁路的价值。
\]
那么我们要维护如下两个东西,就可以在\(O(1)\)内求出一段铁路的价值了。
for( LL i = 1; i <= N; ++i ) Sum[ i ] = Sum[ i - 1 ] + A[ i ];
for( LL i = 1; i <= N; ++i ) SumOfSqr[ i ] = SumOfSqr[ i - 1 ] + A[ i ] * A[ i ];
然后我们考虑打一个最暴力的DP。
我们令\(F[i][j]\)为到第\(i\)个仓库,炸了\(j\)次的最小总价值:
for( LL i = 1; i <= N; ++i )
F[ i ][ 0 ] = Sum[ i ] * Sum[ i ] - SumOfSqr[ i ];
for( LL j = 1; j <= M; ++j )
for( LL i = j + 1; j <= N; ++j ) {
F[ i ][ j ] = INF;
for( LL k = j; k < i; ++k )
F[ i ][ j ] = min( F[ i ][ j ], F[ k ][ j - 1 ] + sqr( Sum[ i ] - Sum[ k ] ) - ( SumOfSqr[ i ] - SumOfSqr[ k ] ) );
}
Ans = F[ N ][ M ];
为了节省空间,我们滚动掉一维:
for( LL i = 1; i <= N; ++i )
F1[ i ] = Sum[ i ] * Sum[ i ] - SumOfSqr[ i ];
for( LL j = 1; j <= M; ++j ) {
for( LL i = j + 1; j <= N; ++j ) {
F2[ i ] = INF;
for( LL k = j; k < i; ++k )
F2[ i ] = min( F2[ i ], F1[ k ] + sqr( Sum[ i ] - Sum[ k ] ) - ( SumOfSqr[ i ] - SumOfSqr[ k ] ) );
}
memcpy( F1, F2, sizeof( F2 ) );
}
Ans = F1[ N ];
最后考虑优化转移复杂度:
设\(l > k\),且从\(l\)转移优于从\(k\)转移,那么就有:
\]
\]
\]
然后我们就可以进行斜率优化了。
斜率优化的具体讲解见这里。
参考程序
#include <bits/stdc++.h>
#define LL long long
using namespace std;
const LL Maxn = 1010;
LL n, m;
LL A[ Maxn ], Sum[ Maxn ], SumOfSqr[ Maxn ], F1[ Maxn ], F2[ Maxn ];
LL L, R, Queue[ Maxn ];
inline LL Sqr( LL x ) { return x * x; }
inline LL GetSum( LL r, LL l ) {
return Sqr( Sum[ r ] - Sum[ l ] ) - ( SumOfSqr[ r ] - SumOfSqr[ l ] );
}
inline bool Less( LL i, LL j, LL T ) {
LL X = 2 * ( Sum[ j ] - Sum[ i ] );
LL Y = ( F1[ j ] + Sqr( Sum[ j ] ) + SumOfSqr[ j ] ) -
( F1[ i ] + Sqr( Sum[ i ] ) + SumOfSqr[ i ] );
return Y < T * X;
}
inline bool Greater( LL i, LL j, LL k ) {
LL X1 = 2 * ( Sum[ j ] - Sum[ i ] );
LL Y1 = ( F1[ j ] + Sqr( Sum[ j ] ) + SumOfSqr[ j ] ) -
( F1[ i ] + Sqr( Sum[ i ] ) + SumOfSqr[ i ] );
LL X2 = 2 * ( Sum[ k ] - Sum[ j ] );
LL Y2 = ( F1[ k ] + Sqr( Sum[ k ] ) + SumOfSqr[ k ] ) -
( F1[ j ] + Sqr( Sum[ j ] ) + SumOfSqr[ j ] );
return X2 * Y1 >= X1 * Y2;
}
void Work() {
for( LL i = 1; i <= n; ++i ) scanf( "%lld", &A[ i ] );
Sum[ 0 ] = 0; SumOfSqr[ 0 ] = 0;
for( LL i = 1; i <= n; ++i ) Sum[ i ] = Sum[ i - 1 ] + A[ i ];
for( LL i = 1; i <= n; ++i ) SumOfSqr[ i ] = SumOfSqr[ i - 1 ] + Sqr( A[ i ] );
for( LL i = 1; i <= n; ++i )
F1[ i ] = GetSum( i, 0 );
for( LL j = 1; j <= m; ++j ) {
L = R = 0; Queue[ R++ ] = j;
memset( F2, 0, sizeof( F2 ) );
for( LL i = j + 1; i <= n; ++i ) {
while( L + 1 < R && Less( Queue[ L ], Queue[ L + 1 ], Sum[ i ] ) )
++L;
F2[ i ] = F1[ Queue[ L ] ] + GetSum( i, Queue[ L ] );
while( L + 1 < R && Greater( Queue[ R - 2 ], Queue[ R - 1 ], i ) )
--R;
Queue[ R++ ] = i;
}
memcpy( F1, F2, sizeof( F2 ) );
}
printf( "%lld\n", F1[ n ] / 2 );
return;
}
int main() {
scanf( "%lld%lld", &n, &m );
while( !( n == 0 && m == 0 ) ) {
Work();
scanf( "%lld%lld", &n, &m );
}
return 0;
}
HDU 2829 [Lawrence] DP斜率优化的更多相关文章
- HDU.2829.Lawrence(DP 斜率优化)
题目链接 \(Description\) 给定一个\(n\)个数的序列,最多将序列分为\(m+1\)段,每段的价值是这段中所有数两两相乘的和.求最小总价值. \(Solution\) 写到这突然懒得写 ...
- HDU 2829 Lawrence(斜率优化DP O(n^2))
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2829 题目大意:有一段铁路有n个站,每个站可以往其他站运送粮草,现在要炸掉m条路使得粮草补给最小,粮草 ...
- HDU 3480 Division DP斜率优化
解题思路 第一步显然是将原数组排序嘛--然后分成一些不相交的子集,这样显然最小.重点是怎么分. 首先,我们写出一个最暴力的\(DP\): 我们令$F[ i ][ j ] $ 为到第\(i\)位,分成\ ...
- hdu 2829 Lawrence(四边形不等式优化dp)
T. E. Lawrence was a controversial figure during World War I. He was a British officer who served in ...
- HDU 2829 Lawrence (斜率DP)
斜率DP 设dp[i][j]表示前i点,炸掉j条边的最小值.j<i dp[i][j]=min{dp[k][j-1]+cost[k+1][i]} 又由得出cost[1][i]=cost[1][k] ...
- hdu 2829 Lawrence(斜率优化DP)
题目链接:hdu 2829 Lawrence 题意: 在一条直线型的铁路上,每个站点有各自的权重num[i],每一段铁路(边)的权重(题目上说是战略价值什么的好像)是能经过这条边的所有站点的乘积之和. ...
- HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化
HDU 2829 区间DP & 前缀和优化 & 四边形不等式优化 n个节点n-1条线性边,炸掉M条边也就是分为m+1个区间 问你各个区间的总策略值最少的炸法 就题目本身而言,中规中矩的 ...
- HDU 3507 [Print Article]DP斜率优化
题目大意 给定一个长度为\(n(n \leqslant 500000)\)的数列,将其分割为连续的若干份,使得 $ \sum ((\sum_{i=j}^kC_i) +M) $ 最小.其中\(C_i\) ...
- HDU 3507 单调队列 斜率优化
斜率优化的模板题 给出n个数以及M,你可以将这些数划分成几个区间,每个区间的值是里面数的和的平方+M,问所有区间值总和最小是多少. 如果不考虑平方,那么我们显然可以使用队列维护单调性,优化DP的线性方 ...
随机推荐
- Centos8 安装ifconfig(net-tools.x86_64)
情况: yum search net-tools.x86_64 没有找到结果 解决: 1.yum search net-tools 2. yum install -y net-tools.x86_64 ...
- java代码--Date类获取当前时间-格式化输出
44:52 阅读数:2299 package cn.Date; import java.text.Format; import java.text.SimpleDateFormat; import ...
- wpf ActualWidth为0解决方法
LocalNewsControl() { var descriptor = DependencyPropertyDescriptor.FromProperty(ActualWidthProperty, ...
- luogu P3226 [HNOI2012]集合选数
luogu 因为限制关系只和2和3有关,如果把数中2的因子和3的因子都除掉,那剩下的数不同的数是不会相互影响,所以每次考虑剩下的数一样的一类数,答案为每类数答案的乘积 如果选了一个数,那么2的因子多1 ...
- git 基础命令 学习总结
首先介绍一个git 里工作流的概念: 你的本地仓库由 git 维护的三棵“树”组成.第一个是你的 工作目录,它持有实际文件:第二个是 缓存区(Index),它像个缓存区域,临时保存你的改动:最后是 H ...
- 取出input内的空格
onkeyup='this.value=this.value.replace(' ','')'
- 架构师成长之路5.7-Saltstack数据系统
点击架构师成长之路 架构师成长之路5.7-Saltstack数据系统 1. Saltstack的两种数据系统 Grains Pollars 2. Saltstack数据系统---Grains Grai ...
- RE 逆向工程初学者指南:方法和工具
简评: RE 两种分析,静态.动态.好好分析静态因为能够解决 70 % 的问题.介绍了一些工具和方法.Enjoy yourself. 最近几天,我决定试水逆向工程,即使在计算机和编程相关领域有一定的基 ...
- Turing Tree HDU - 3333 (树状数组,离线求区间元素种类数)
After inventing Turing Tree, 3xian always felt boring when solving problems about intervals, because ...
- java将一数组乱序排列
JAVA的Collections类中shuffle方法模拟了“洗牌”动作可以对list列表进行随机排序.如果一定要自己写,算法也很简单:假设数组array长度为n.用标准随机函数rand(n)生成[0 ...