书架_纪中2931_dp+堆+单调队列优化

Description

当Farmer John闲下来的时候,他喜欢坐下来读一本好书。

多年来,他已经收集了N本书 (1 <= N <= 100,000)。

他想要建立一个多层书架,来存放它们。

每本书 i 拥有一个宽度 W(i)和一个高度 H(i)。

所有的书需要按顺序,放到书架的每一层。

举例来说,第一层书架放k本书,应该放书1…k;第二层书架从第k+1本书开始放……。

每层书架的宽度最多为L (1 <= L <= 1,000,000,000)。

每层书架的高度为该层最高的那本书的高度。

书架的总高度为每层书架高度之和。

请帮FJ计算书架可能的最小总高度。

Input

第1行:两个空格隔开的整数:N和L

第2..N+1行:第i+1行包含两个空格隔开的整数:H(i) 和 W(i) 。(1 <= H(i) <= 1,000,000; 1 <= W(i) <= L)。

Output

第1行:书架可能的最小总高度

Sample Input

5 10

5 7

9 2

8 5

13 2

3 8

Sample Output

21

Hint

[样例解释]

3层书架,第1层放书1(高5,宽7),第2层放书2..4(高13,宽9),第3层放书5(高3,宽8)

[数据范围]

40%的数据满足 N<=2000

翔法

传送大法——

媳妇

连续做了几天题,用脚趾都想到第三题是dp

  • 首先想到状态转移方程f[i][j]表示前i本书放了j层
    • 于是就boom~
  • 又想到直接删掉一维,于是f[i]表示前i本书,且第i本刚好是当前层的最后一本,则有
    f[i]=min(f[j]+max(h[j],h[j+1],h[j+2]...h[i]))
  • 且满足条件
    j=1iw[j]<=L
  • 对于j的位置可以用单调队列求,最小的f值也能通过对堆得维护得出
  • 于是喜爱偷懒哦不,钻研的我们找到了c++的set头文件,定义如下

    set/multiset会根据待定的排序准则,自动将元素排序。两者不同在于前者不允许元素重复,而后者允许。

  • 于是乎这个神奇的set算法时间复杂度为

    logn

    100000的数据下表现优良
    pascal太蛋疼于是就没有打惹

源代码/c++

#include <stdio.h>  
#include <set>
using namespace std;  
long long que[100100],a[100100],dp[100100],b[100100]; 
long long n,m,j,front=1,rear=1,p=1;
multiset <long long>t;
int main()  
{      
  scanf("%lld%lld",&n,&m);   
  for(long long i=1;i<=n;i++) scanf("%lld%lld",&a[i],&b[i]);
  dp[1]=a[1];
  que[rear]=1;  
  long long sum=b[1];  
  for(long long i=2;i<=n;i++){  
    sum+=b[i];  
    while(sum>m) sum-=b[p++];
    while(front<=rear&&a[i]>=a[que[rear]]) t.erase(dp[que[rear-1]]+a[que[rear--]]);
    rear=rear+1;
    que[rear]=i;
    if (front<rear) t.insert(dp[que[rear-1]]+a[que[rear]]);
    while(que[front]<p&&front<=rear) t.erase(dp[que[front]]+a[que[++front]]);
    dp[i]=dp[p-1]+a[que[front]];  
    j=*t.begin();
    if ((j<dp[i])&&(j!=0)) dp[i]=j;          
  }  
  printf("%lld\n",dp[n]);
  return 0;  
}  
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值