问题分析

首先,如果一个人的\(w\)和\(h\)均小于另一个人,那么这个人显然可以被省略。如果我们将剩下的人按\(w[i]\)递增排序,那么\(h[i]\)就是递减。

之后我们考虑DP。

我们设\(f[i][j]\)为到第\(i\)个人,打了\(j\)个洞的花费。于是我们可以得到如下DP过程:

for( LL i = 1; i <= N; ++i ) F[ i ][ 1 ] = w[ i ] * h[ 1 ];
for( LL j = 2; j <= K; ++j )
for( LL i = j; i <= N; ++i ) {
f[ i ][ j ] = INF;
for( LL k = j - 1; k < i; ++k )
F[ i ][ j ] = min( F[ i ][ j ], F[ k ][ j - 1 ] + w[ i ] * h[ k + 1 ] );
}
Ans = F[ N ][ K ];

我们将第二维滚动掉,节省空间:

for( LL i = 1; i <= N; ++i ) F1[ i ] = w[ i ] * h[ 1 ];
for( LL j = 2; j <= K; ++j ) {
for( LL i = j; i <= N; ++i ) {
F2[ i ] = INF;
for( LL k = j - 1; k < i; ++k )
F2[ i ] = min( F2[ i ], F1[ k ] + w[ i ] * h[ k + 1 ] );
}
memcpy( F1, F2, sizeof( F2 ) );
}
Ans = F1[ N ][ K ];

再考虑优化最里面一层循环:

设\(l>k\)且从\(l\)转移优于从\(k\)转移,那么就有

\[F1[l]+w[i]*h[l+1]<F1[k]+w[i]*h[k+1]
\]

化简,得

\[\frac{F_1[l]-F_1[k]}{h[k+1]-h[l+1]}<w[i]
\]

然后就可以斜率优化了。具体的斜率优化讲解可以看这里

参考程序

#include <bits/stdc++.h>
#define LL long long
using namespace std; const LL INF = 1e18 + 10;
const LL MaxN = 50010, MaxK = 110;
LL N, K;
struct CitizenAttribute {
LL Width, Hight;
CitizenAttribute( LL Width_ = 0, LL Hight_ = 0 ) {
Width = Width_; Hight = Hight_; return;
}
bool operator < ( const CitizenAttribute Other ) const {
return Width < Other.Width || Width == Other.Width && Hight > Other.Hight;
}
};
CitizenAttribute Citizens[ MaxN ];
bool IsSkiped[ MaxN ];
LL L, R, Queue[ MaxN ], F1[ MaxN ], F2[ MaxN ];
LL NumAfterSkip; inline void Clear() {
memset( Citizens, 0, sizeof( Citizens ) );
memset( IsSkiped, false, sizeof( IsSkiped ) );
memset( F1, 0, sizeof( F1 ) );
return;
} inline void SkipContainedCitizen() {
CitizenAttribute Last = CitizenAttribute( 0, 0 );
for( LL i = N; i >= 1; --i )
if( Citizens[ i ].Hight <= Last.Hight ) IsSkiped[ i ] = true;
else Last = Citizens[ i ];
NumAfterSkip = 0;
for( LL i = 1; i <= N; ++i )
if( !IsSkiped[ i ] )
Citizens[ ++NumAfterSkip ] = Citizens[ i ];
return;
} inline bool Less( LL i, LL j, LL Limit ) {
LL DeltaY = F1[ j ] - F1[ i ];
LL DeltaX = Citizens[ i + 1 ].Hight - Citizens[ j + 1 ].Hight;
return DeltaY <= Limit * DeltaX;
} inline bool Greater( LL i, LL j, LL k ) {
LL DeltaY1 = F1[ j ] - F1[ i ];
LL DeltaY2 = F1[ k ] - F1[ j ];
LL DeltaX1 = Citizens[ i + 1 ].Hight - Citizens[ j + 1 ].Hight;
LL DeltaX2 = Citizens[ j + 1 ].Hight - Citizens[ k + 1 ].Hight;
return DeltaY1 * DeltaX2 >= DeltaY2 * DeltaX1;
} void Work() {
LL Ans = INF;
Clear();
for( LL i = 1; i <= N; ++i )
scanf( "%lld%lld", &Citizens[ i ].Width, &Citizens[ i ].Hight );
sort( Citizens + 1, Citizens + N + 1 );
SkipContainedCitizen();
for( LL i = 1; i <= NumAfterSkip; ++i ) F1[ i ] = Citizens[ i ].Width * Citizens[ 1 ].Hight;
Ans = min( Ans, F1[ NumAfterSkip ] );
for( LL j = 2; j <= K && j <= NumAfterSkip; ++j ) {
memset( F2, 0, sizeof( F2 ) );
L = R = 0; memset( Queue, 0, sizeof( Queue ) );
Queue[ R++ ] = j - 1;
for( LL i = j; i <= NumAfterSkip; ++i ) {
while( L + 1 < R && Less( Queue[ L ], Queue[ L + 1 ], Citizens[ i ].Width ) )
++L;
F2[ i ] = F1[ Queue[ L ] ] + Citizens[ Queue[ L ] + 1 ].Hight * Citizens[ i ].Width;
while( L + 1 < R && Greater( Queue[ R - 2 ], Queue[ R - 1 ], i ) )
--R;
Queue[ R++ ] = i;
}
memcpy( F1, F2, sizeof( F2 ) );
Ans = min( Ans, F1[ NumAfterSkip ] );
}
printf( "%lld\n", Ans );
return;
} int main() {
while( scanf( "%lld%lld", &N, &K ) == 2 )
Work();
return 0;
}

HDU 3669 [Cross the Wall] DP斜率优化的更多相关文章

  1. HDU 3669 Cross the Wall(斜率DP+预处理)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3669 题目大意:有n(n<=50000)个矩形,每个矩形都有高和宽,你可以在墙上最多挖k个洞使得 ...

  2. hdu 3669 Cross the Wall(斜率优化DP)

    题目连接:hdu 3669 Cross the Wall 题意: 现在有一面无限大的墙,现在有n个人,每个人都能看成一个矩形,宽是w,高是h,现在这n个人要通过这面墙,现在只能让你挖k个洞,每个洞不能 ...

  3. 动态规划DP的斜率优化 个人浅解 附HDU 3669 Cross the Wall

    首先要感谢叉姐的指导Orz 这一类问题的DP方程都有如下形式 dp[i] = w(i) + max/min(a(i)*b(j) + c(j)) ( 0 <= j < i ) 其中,b, c ...

  4. HDU 3669 Cross the Wall

    题目大意 给定 \(N\) 个矩形的宽和高, \((h_1, w_1), (h_2, w_2), \dots, (h_n w_n)\) . 现需要确定 \(k\) (\(k \le K\), \(K\ ...

  5. HDU 3507 Print Article(DP+斜率优化)

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

  6. HDU 2993 MAX Average Problem dp斜率优化

    MAX Average Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Othe ...

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

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

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

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

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

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

随机推荐

  1. redis 学习(3)-- String 类型

    redis 学习(3)-- String 类型 String-结构 结构:Key-Value对 Value:可以是字符串.数字,也可以是二进制数组 限制:Value最大值为512MB String-常 ...

  2. 获取iframe中的tree

    window.frames["iframe_name"].document.getElementById("..."); 或者 window.frames['i ...

  3. thinkphp3.2.3 自动验证 unique 出错的解决办法

    场景:修改数据时,唯一验证name字段出错,提示已存在. 排查: 1.传入的参数是否包含主键,因为 D('模型名')->create() 会自动判断是否是新增或者修改,根据传入的参数判断是否包含 ...

  4. 07 Python之协程

    协程: 协程是一种用户态的轻量级线程, 即协程是由用户程序自己控制调度的 1.Greenlet import time # import greenlet from greenlet import g ...

  5. IOS手机伪类a:active失效

    IOS手机伪类a:active失效:点击更改颜色,松开恢复 解决方案:OS系统的移动设备中,需要在按钮元素或body/html上绑定一个touchstart事件才能激活:active状态 docume ...

  6. Slimvoice快速而小巧

    这可行吗?绝对没问题.完全加载的最大页面只有230 KB.因为所有内容都被缓存和压缩,所以随后查看的每个页面只有大约6 KB,这比我见过的具有相同功能的SPA要小得多. Slimvoice快速而小巧, ...

  7. IDEA + SpringBoot + maven 项目文件说明

    Springboot + maven + IDEA + git 项目文件介绍 1..gitignore  分布式版本控制系统git的配置文件,意思为忽略提交 在 .gitingore 文件中,遵循相应 ...

  8. postgres中的函数

    1.编写一个只有入参,没有出参的函数: CREATE OR REPLACE FUNCTION add(a NUMERIC, b NUMERIC) RETURNS NUMERIC AS $$ SELEC ...

  9. Shell编程备份数据库

    案例: 在/usr/sbin/建立Shell文件 备份后查看目录: 然后进行crontab任务调度: #每天凌晨两点十分调度一次 * * * /usr/sbin/mysql_db.sh

  10. monkey命令大全

    一.认识monkey Monkey 就是SDK中附带的一个工具.Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中: 它向系统发送伪随机的用户事件流(如按键输入.触摸屏输入 ...