You have a multiset containing several integers. Initially, it contains a_1 elements equal to 1, a_2 elements equal to 2, ..., a_n elements equal to n.

You may apply two types of operations:

  * choose two integers l and r (l ≤ r), then remove one occurrence of l, one occurrence of l + 1, ..., one occurrence of r from the multiset. This operation can be applied only if each number from l to r occurs at least once in the multiset; 
  * choose two integers i and x (x ≥ 1), then remove x occurrences of i from the multiset. This operation can be applied only if the multiset contains at least x occurrences of i. 



What is the minimum number of operations required to delete all elements from the multiset?

Input

The first line contains one integer n (1 ≤ n ≤ 5000).

The second line contains n integers a_1, a_2, ..., a_n (0 ≤ a_i ≤ 10^9).

Output

Print one integer — the minimum number of operations required to delete all elements from the multiset.

Examples

Input


4
1 4 1 1


Output


2


Input


5
1 0 1 0 1


Output


3
import java.io.*;
import java.util.*;
import java.util.function.IntPredicate;

public class MainE {

    static int N;
    static int[] A;

    public static void main(String[] args) {
        var sc = new FastScanner(System.in);
        N = sc.nextInt();
        A = sc.nextIntArray(N);
        System.out.println( solve() );
    }

    private static long solve() {
        var seg = new RangeGet(N, RangeGet.MIN);
        for (int i = 0; i < N; i++) {
            seg.update(i, A[i]);
        }

        long ans = 0;
        var ranges = segmentation(A, 0, N, a -> a > 0);
        for (int[] range : ranges) {
            ans += calc(range[0], range[1], 0, seg);
        }
        return ans;
    }

    // [l, r)
    static long calc(int l, int r, long d, RangeGet seg) {
        long min = seg.query(l, r);
        long cost = min - d;

        if( cost >= r-l ) return r-l;

        var ranges = segmentation(A, l, r, a -> a > min);
        for (int[] range : ranges) {
            cost += calc(range[0], range[1], min, seg);
        }
        return Math.min(cost, r-l);
    }

    static List<int[]> segmentation(int[] A, int L, int R, IntPredicate P) {
        var ranges = new ArrayList<int[]>();
        var l = -1;
        for (var i = L; i < R; i++) {
            if( l == -1 ) {
                if( P.test(A[i]) ) {
                    l = i;
                }

            } else {
                if( !P.test(A[i]) ) {
                    ranges.add(new int[]{l, i});
                    l = -1;
                }
            }
        }
        if( l != - 1 ) {
            ranges.add(new int[]{l, R});
        }
        return ranges;
    }

    // 一点更新 範囲取得
    static class RangeGet {

        interface Monoid {
            long identity();
            long apply(long a, long b);
        }

        static Monoid MOD_SUM(int mod) {
            return new Monoid() {
                public long identity() { return 0; }
                public long apply(long a, long b) {
                    long c = a + b;
                    if( c >= mod ) {
                        c %= mod;
                    }
                    return c;
                }
            };
        }

        static Monoid SUM = new Monoid() {
            public long identity() { return 0; }
            public long apply(long a, long b) { return a + b; }
        };

        static Monoid MAX = new Monoid() {
            public long identity() { return Long.MIN_VALUE / 2; }
            public long apply(long a, long b) { return Math.max(a, b); }
        };

        static Monoid MIN = new Monoid() {
            public long identity() { return Long.MAX_VALUE / 2; }
            public long apply(long a, long b) { return Math.min(a, b); }
        };

        int size;
        long[] tree;
        Monoid m;
        long identity;

        RangeGet(int size, Monoid m) {
            this.size = 1;
            while( this.size < size ) this.size *= 2;
            this.tree = new long[this.size*2];
            this.m = m;
            this.identity = m.identity();
            if( this.identity != 0 ) {
                Arrays.fill(this.tree, this.identity);
            }
        }

        void update(int idx, long v) {
            idx += size;
            tree[idx] = v;

            while(idx > 0) {
                idx /= 2;
                tree[idx] = m.apply(tree[idx*2], tree[idx*2+1]);
            }
        }

        // [from, to)
        long query(int from, int to) {
            return _query(from, to, 1, 0, size);
        }

        private long _query(int from, int to, int idx, int l, int r) {
            if (r <= from || to <= l) return identity;

            if (from <= l && r <= to) {
                return tree[idx];

            } else {
                int mid = (l+r)/2;
                long vl = _query(from, to, idx*2, l, mid);
                long vr = _query(from, to, idx*2+1, mid, r);
                return m.apply(vl, vr);
            }
        }

        long get(int idx) {
            return tree[idx+size];
        }
    }

    @SuppressWarnings("unused")
    static class FastScanner {
        private final BufferedReader reader;
        private StringTokenizer tokenizer;

        FastScanner(InputStream in) {
            reader = new BufferedReader(new InputStreamReader(in));
            tokenizer = null;
        }

        String next() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    tokenizer = new StringTokenizer(reader.readLine());
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken();
        }

        String nextLine() {
            if (tokenizer == null || !tokenizer.hasMoreTokens()) {
                try {
                    return reader.readLine();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            return tokenizer.nextToken("\n");
        }

        long nextLong() {
            return Long.parseLong(next());
        }

        int nextInt() {
            return Integer.parseInt(next());
        }

        int[] nextIntArray(int n) {
            var a = new int[n];
            for (int i = 0; i < n; i++) a[i] = nextInt();
            return a;
        }

        int[] nextIntArray(int n, int delta) {
            var a = new int[n];
            for (int i = 0; i < n; i++) a[i] = nextInt() + delta;
            return a;
        }

        long[] nextLongArray(int n) {
            var a = new long[n];
            for (int i = 0; i < n; i++) a[i] = nextLong();
            return a;
        }
    }

    static void writeLines(int[] as) {
        var pw = new PrintWriter(System.out);
        for (var a : as) pw.println(a);
        pw.flush();
    }

    static void writeLines(long[] as) {
        var pw = new PrintWriter(System.out);
        for (var a : as) pw.println(a);
        pw.flush();
    }

    static void writeSingleLine(int[] as) {
        var pw = new PrintWriter(System.out);
        for (var i = 0; i < as.length; i++) {
            if (i != 0) pw.print(" ");
            pw.print(as[i]);
        }
        pw.println();
        pw.flush();
    }

    static void debug(Object... args) {
        var j = new StringJoiner(" ");
        for (var arg : args) {
            if (arg == null) j.add("null");
            else if (arg instanceof int[]) j.add(Arrays.toString((int[]) arg));
            else if (arg instanceof long[]) j.add(Arrays.toString((long[]) arg));
            else if (arg instanceof double[]) j.add(Arrays.toString((double[]) arg));
            else if (arg instanceof Object[]) j.add(Arrays.toString((Object[]) arg));
            else j.add(arg.toString());
        }
        System.err.println(j.toString());
    }
}
