题目给你一个积木(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 <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <iostream>
#include <queue>
#include <map>
#include <set>
#include <vector>
using namespace std;
#define inf 2147483647
int min(int a,int b)
{return a<b?a:b;}
int tm[100005];
int ll[100005];
int rr[100005];
int main()
{
int n,i,j,tt,m;
scanf("%d",&n);
int h=1;
int e=n;
for (i=1;i<=n;i++)
scanf("%d",&tm[i]);
tm[0]=tm[n+1]=inf-1;
for (i=1;i<=n;i++)
ll[i]=min(i,min(tm[i],ll[i-1]+1));
for (i=n;i>=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;
}