Codeforces Round #318 [RussianCodeCup Thanks-Round] (Div. 2) D 雙向dp

CrossDolphin發表於2016-07-13



連結:戳這裡


D. Bear and Blocks
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
Limak is a little bear who loves to play. Today he is playing by destroying block towers. He built n towers in a row. The i-th tower is made of hi identical blocks. For clarification see picture for the first sample.

Limak will repeat the following operation till everything is destroyed.

Block is called internal if it has all four neighbors, i.e. it has each side (top, left, down and right) adjacent to other block or to the floor. Otherwise, block is boundary. In one operation Limak destroys all boundary blocks. His paws are very fast and he destroys all those blocks at the same time.

Limak is ready to start. You task is to count how many operations will it take him to destroy all towers.

Input
The first line contains single integer n (1 ≤ n ≤ 105).

The second line contains n space-separated integers h1, h2, ..., hn (1 ≤ hi ≤ 109) — sizes of towers.

Output
Print the number of operations needed to destroy all towers.

Examples
input
6
2 1 4 6 2 2
output
3
input
7
3 3 3 1 3 3 3
output
2
Note
The picture below shows all three operations for the first sample test. Each time boundary blocks are marked with red color.
After first operation there are four blocks left and only one remains after second operation. This last block is destroyed in third operation.


題意:

給出n個高度的n座積木,現在要拆積木,如果一塊積木能拆需要滿足的條件是

這塊積木的上下左右至少有一塊是空著的,而且拆積木的時候,當前所有能拆的積木只需要一次操作就能拆除

問最少需要拆多少次可以拆完


思路:

一開始想著模擬過程,但是給出的如果是1e5個1e9高度的積木,那麼需要的次數是 1e5*(1e5/2)會T

換個思路,我們可以統計出每列積木的最小操作次數,怎麼統計呢?

雙向dp,先從左往右統計當前第i列從左到右至少需要的操作次數

轉移方程也就是 dp[i]=min{i,a[i],dp[i-1]+1}

i :表示從左往右一列一列消去需要的操作次數

a[i]:表示從上往下一塊一塊消去需要的操作次數

dp[i-1]+1:表示前一塊已經消去,那麼第i塊也只需要dp[i-1]+1次

同理,在統計一遍從右往左的最小!

這樣我就知道了當前的第i列從左往右和從右往左的最小操作次數,每次選擇當前兩個值的最小值

再去用ans更新這n個值得最大值也就是答案了


程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<string>
#include<vector>
#include <ctime>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<iomanip>
#include<cmath>
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define maxn 0x3f3f3f3f
#define MAX 1000100
///#pragma comment(linker, "/STACK:102400000,102400000")
typedef long long ll;
typedef unsigned long long ull;
#define INF (1ll<<60)-1
using namespace std;
int n;
int a[100100];
int L[100100],R[100100];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    mst(L,127);
    mst(R,127);
    L[0]=0;R[n+1]=0;
    for(int i=1;i<=n;i++){
        L[i]=min(L[i],a[i]);
        L[i]=min(L[i],i);
        L[i]=min(L[i],L[i-1]+1);
    }
    for(int i=n;i>=1;i--){
        R[i]=min(R[i],a[i]);
        R[i]=min(R[i],n-i+1);
        R[i]=min(R[i],R[i+1]+1);
    }
    int ans=0;
    for(int i=1;i<=n;i++){
        ans=max(ans,min(L[i],R[i]));
    }
    cout<<ans<<endl;
    return 0;
}


相關文章