cf#318-D - Bear and Blocks-双向dp

题目给你一个积木(n个数字、表示第i列的高度为h[i])(类似于俄罗斯方块)

每次进行一次X操作,X操作计算把所有边缘的小正方形去掉(也就是把与空白处接触的格子都去掉)

问你 给出一个图形 要做多少次操作才能把所有的格子去掉

n最大10^5    h最大10^9

一开始想直接模拟,每次贪心去掉每一列的能去掉的格子

最糟糕的情况 是n*h 的一个矩形    n取10^5    h取10^9

直接模拟要做  n/2次,每次o(n)的操作  复杂度O(n^2)显然超时


后来想dp、一直认为 要推出dp[i]、得需要得到dp[i-1] 和dp[i+1] 所以没做出来


后来看了别人的题解 原来是先从左右到推一遍dp 再从右到左,

然后 第i列 所需要最少的 X操作次数就能消掉 的ans[i] 应该为 min(dp_left[i],dp_right[i])

所以最后取一个最大的ans[i]就是 要求的答案了

注意设tm[0]=tm[n+1]=inf-1 、 不减1待会运算会爆掉


递推公式为dp_left[i]=min(i,h[i],dp_left[i-1]+1)

表示当前最小步数 为 

A、其序号(消到第i次,第i列就完全暴露在空气中,就可以直接删了)

B、或者dp_left[i]-1 (前一列消除完,第i列就完全暴露在空气中,下一次操作就可以直接删了第i列)

C、或者 h[i](因为每次至少高度会降低1,所以h[i]次后必然也完全消除了)

三者最小之一


右侧同理

代码:

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
using namespace std;
#define inf 2147483647
int min(int a,int b)
{return a=1;i--) 
		rr[i]=min(n-i+1,min(tm[i],rr[i+1]+1));  

	int maxx=0;
	for (i=1;i<=n;i++)
	{
		tm[i]=min(ll[i],rr[i]);
		if (tm[i]>maxx)  maxx=tm[i];
	}
	printf("%d\n",maxx);

	
	return 0;
	
}


你可能感兴趣的:(CF,dp-----------)