题目大意
有 \(N\) 本书,第 \(i\) 本书宽 \(w_i\),高 \(h_i\)。
我们需要将这些这些书分成几个区间,每个区间所有书的宽度之和不超过 \(L\)。
书架的高度为每个区间最高的书的高度之和,求书架最小高度。
题目分析
我们令 \(dp[i]\) 表示到第 \(i\) 本书为止,书架的最小高度。
对于每一个状态 \(dp[i]\),都可能由两种方法转移而来:
- 再开一个书架。此时有
\(h[i]\) 表示每一本书的高度。
- 插入之前的书架,那么当然需要知道前面数的最大高度,\(O(N)\) 查找即可。有
\(\operatorname{maxsum}\) 表示最大高度。
代码
//2021/9/6
//2021/9/8
#include <iostream>
#include <cstdio>
#include <algorithm>
#define debug(c) cerr<<#c<<" = "<<c<<endl
namespace Newstd
{
inline int read()
{
char c;
bool flag=false;
while((c=getchar())<'0' || c>'9')
{
if(c=='-') flag=true;
}
int res=c-'0';
while((c=getchar())>='0' && c<='9')
{
res=(res<<3)+(res<<1)+c-'0';
}
return flag?-res:res;
}
inline void print(int x)
{
if(x<0)
{
putchar('-');x=-x;
}
if(x>9)
{
print(x/10);
}
putchar(x%10+'0');
}
}
using namespace Newstd;
using namespace std;
const int ma=100005;
int h[ma],w[ma],sum[ma],dp[ma];
int n,m;
int main(void)
{
n=read(),m=read();
for(register int i=1;i<=n;i++)
{
h[i]=read(),w[i]=read();
sum[i]=sum[i-1]+w[i];
dp[i]=(1<<29);
}
for(register int i=1;i<=n;i++)
{
dp[i]=dp[i-1]+h[i];
int tmp=h[i];
for(register int j=i-1;j>=1 && sum[i]-sum[j-1]<=m;j--)
{
tmp=max(tmp,h[j]);
dp[i]=min(dp[i],dp[j-1]+tmp);
}
}
print(dp[n]);
return 0;
}