1. 程式人生 > 其它 >[USACO12OPEN]Bookshelf S

[USACO12OPEN]Bookshelf S

洛谷題面

題目大意

\(N\) 本書,第 \(i\) 本書寬 \(w_i\),高 \(h_i\)

我們需要將這些這些書分成幾個區間,每個區間所有書的寬度之和不超過 \(L\)

書架的高度為每個區間最高的書的高度之和,求書架最小高度。

題目分析

我們令 \(dp[i]\) 表示到第 \(i\) 本書為止,書架的最小高度。

對於每一個狀態 \(dp[i]\),都可能由兩種方法轉移而來:

  1. 再開一個書架。此時有
\[dp[i]=dp[i-1]+h[i] \]

\(h[i]\) 表示每一本書的高度。

  1. 插入之前的書架,那麼當然需要知道前面數的最大高度,\(O(N)\) 查詢即可。有
\[dp[i] = \min\{dp[i],dp[j-1]+\operatorname{maxsum}\} \]

\(\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;
}