您的位置:首页 > Web前端

codeforces 448C Painting Fence

2016-03-01 20:27 253 查看
C. Painting Fence

time limit per test
1 second

memory limit per test
512 megabytes

input
standard input

output
standard output

Bizon the Champion isn't just attentive, he also is very hardworking.

Bizon the Champion decided to paint his old fence his favorite color, orange. The fence is represented as n vertical planks, put in a row. Adjacent planks have no gap between
them. The planks are numbered from the left to the right starting from one, the i-th plank has the width of 1 meter and the height of ai meters.

Bizon the Champion bought a brush in the shop, the brush's width is 1 meter. He can make vertical and horizontal strokes with the brush. During a stroke the brush's full
surface must touch the fence at all the time (see the samples for the better understanding). What minimum number of strokes should Bizon the Champion do to fully paint the fence? Note that you are allowed to paint the same area of the fence multiple times.

Input

The first line contains integer n (1 ≤ n ≤ 5000) — the number of fence planks. The second line contains n space-separated
integersa1, a2, ..., an (1 ≤ ai ≤ 109).

Output

Print a single integer — the minimum number of strokes needed to paint the whole fence.

Examples

input
5
2 2 1 2 1


output
3


input
2
2 2


output
2


input
1
5


output
1


Note

In the first sample you need to paint the fence in three strokes with the brush: the first stroke goes on height 1 horizontally along all the planks. The second stroke goes on height 2 horizontally and
paints the first and second planks and the third stroke (it can be horizontal and vertical) finishes painting the fourth plank.

In the second sample you can paint the fence with two strokes, either two horizontal or two vertical strokes.

In the third sample there is only one plank that can be painted using a single vertical stroke.

*****************************************************************************************************************************

solution:cf上的很多题都有其特殊的“特性”,把握住特性就能很好地解决问题。比如这个问题中,我们要把握住两点:一,一次涂漆尽可能多涂(ps:这不是废话吗);二,就是一行如果水平涂满了,那这行下面的所有行都是水平涂满的,这是为什么呢?简单证明一下:如果下面那些行中有些是竖涂的,那么请你想想,它为什么不涂到一列的顶呢?否则不是浪费了吗?

所以,我们可以得出,对下标为l--r的一段墙,我们有两种策略,一种是全部竖涂(参考前面的,想想为什么),另一种是横涂到这段墙的最小值(把l--r全部能涂的行从底下开始都涂了),再把这段分成几个小段累加(你也许会问,怎么不全部横涂呢?这是因为受到高度的限制,所以必须根据最小高度分成几段分别处理),每次返回两种策略的最小值,用分治来实现。

找最小值可以用线段树来优化。

#include<cstdio>
#include<iostream>
#define p1 id<<1#define p2 (id<<1)+1using namespace std;
int a[100005],tree[450000];
int n,ans;
void build(int id,int l,int r)
{
if(l==r)
{
tree[id]=a[l];
return;
}
int mid=(l+r)/2;
build(p1,l,mid);
build(p2,mid+1,r);
tree[id]=min(tree[p1],tree[p2]);
}
int lookup(int id,int l,int r,int x,int y)
{
if(l>y||r<x) return -1;
if(x<=l&&r<=y) return tree[id];
int mid=(l+r)/2;
int s1=lookup(p1,l,mid,x,y);
int s2=lookup(p2,mid+1,r,x,y);
if(s1==-1) return s2;
if(s2==-1) return s1;
return min(s1,s2);
}
int dfs(int l,int r,int under)
{
if(l>r) return 0;
int mint=lookup(1,1,n,l,r);
int s1,s2,k;
s1=r-l+1;
s2=mint-under;
k=l;
for(int i=l;i<=r;i++)
if(a[i]==mint)
{
s2=s2+dfs(k,i-1,mint);
k=i+1;
}
s2=s2+dfs(k,r,mint);
return min(s1,s2);
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
build(1,1,n);
ans=min(n,dfs(1,n,0));
cout<<ans<<endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: