题目链接:
题目大意:
给出n个连续塔,每个塔有高度hi,每次取走最外层的块,问需要多少次操作能够拿光所有的块。
题目分析:
- 首先我们可以知道第一次操作时,对于每个塔的变化满足如下的公式:
hi=min(hi?1,hi?1,hi+1) - 每次操作都满足如下的递推式,我们递推一下得到第k次操作第i的塔的高度:
hi=max(0,minj=0i{min(hi?j?(k?j),hi+j?(k?j)}?hi=max(0,minj=0i{min(hi?j+j?k,hi+j+j?k}因为k是常数,所以对于,每一项我们找到的就是最小的hi?j+j和hi+j+j,这可用线段树进行维护。
- 而且要设定两个虚拟的高度为0的塔,分别放在这一堆塔的两头,这样能够维护两侧的在每次操作拿光的情况。
- 至于线段树维护的部分,就是遍历i两次,分别从小到大和从大到小,每次修改之前遍历过的位置为所要的状态,也就是之前遍历过的位置区间内全部加1,然后统计[0,i]的最小值,右侧的同理。
AC代码:
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>
#define MAX 100007
using namespace std;
int n;
int l[MAX],r[MAX],h[MAX];
struct Tree
{
int l,r,minn,lazy;
}tree[MAX<<2];
void push_up ( int u )
{
tree[u].minn = min ( tree[u<<1].minn , tree[u<<1|1].minn );
}
void build ( int u , int l , int r )
{
tree[u].l = l;
tree[u].r = r;
tree[u].lazy = 0;
int mid = l+r>>1;
if ( l == r )
{
tree[u].minn = h[l];
return;
}
build ( u<<1 , l , mid );
build ( u<<1|1 , mid+1 , r );
push_up ( u );
}
void push_down ( int u )
{
int ll = tree[u].lazy;
tree[u].lazy = 0;
if ( ll )
{
tree[u<<1].lazy += ll;
tree[u<<1|1].lazy += ll;
tree[u<<1].minn += ll;
tree[u<<1|1].minn += ll;
}
}
void update ( int u , int left , int right )
{
int l = tree[u].l;
int r = tree[u].r;
int mid = l+r>>1;
if ( left <= l && r <= right )
{
tree[u].minn += 1;
tree[u].lazy += 1;
return;
}
push_down ( u );
if ( left <= mid && right >= l )
update ( u<<1 , left , right );
if ( left <= r && right > mid )
update ( u<<1|1 , left , right );
push_up ( u );
}
int query ( int u , int left , int right )
{
int l = tree[u].l;
int r = tree[u].r;
int mid = l+r>>1;
if ( left <= l && r <= right )
return tree[u].minn;
push_down ( u );
int ret = 1<<29;
if ( left <= mid && right >= l )
ret = min ( ret , query ( u<<1 , left , right ) );
if ( left <= r && right > mid )
ret = min ( ret , query ( u<<1|1 , left , right ) );
return ret;
}
int main ( )
{
while ( ~scanf ( "%d" , &n ) )
{
h[0] = h[n+1] = 0;
for ( int i = 1; i <= n ; i++ )
scanf ( "%d" , &h[i] );
build ( 1 , 0 , n+1 );
for ( int i = 1 ; i <= n ; i++ )
{
update ( 1 , 0 , i-1 );
l[i] = query ( 1 , 0 , i );
}
build ( 1 , 0 , n+1 );
for ( int i = n ; i > 0 ; i-- )
{
update ( 1 , i+1 , n+1 );
r[i] = query ( 1 , i , n+1 );
}
int ans = 0;
for ( int i = 1 ; i <= n ; i++ )
{
//cout << "YES : " << l[i] << " " << r[i] << endl;
ans = max ( ans , min ( l[i] , r[i] ));
}
printf ( "%d\n" , ans );
}
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
时间: 2024-10-10 01:53:53