#include <bits/stdc++.h>
using namespace std;
template <class T>
T read() {
  T value;
  cin >> value;
  return value;
}
int read_int() { return read<int>(); }
size_t read_size() { return read<size_t>(); }
long long read_ll() { return read<long long>(); }
string read_string() { return read<string>(); }
template <class T>
void read_vector(vector<T> &a, size_t size) {
  a.resize(size);
  for (T &value : a) cin >> value;
}
template <class T1, class T2>
void read_pairs(vector<pair<T1, T2>> &a, size_t size) {
  a.resize(size);
  for (auto &value : a) cin >> value.first >> value.second;
}
void read_iii(vector<pair<pair<int, int>, int>> &a, size_t size) {
  a.resize(size);
  for (pair<pair<int, int>, int> &value : a)
    cin >> value.first.first >> value.first.second >> value.second;
}
void add_to_each(vector<int> &a, int delta) {
  for (int &value : a) value += delta;
}
void add_to_each(vector<pair<int, int>> &a, int delta) {
  for (pair<int, int> &value : a) {
    value.first += delta;
    value.second += delta;
  }
}
const char SPACE = ' ', ENDL = '\n';
template <class T>
void print(vector<T> &a, char sep = SPACE) {
  for (T &value : a) cout << value << sep;
  cout << '\n';
}
template <class T>
vector<int> compress(vector<T> &values) {
  vector<T> sorted = values;
  sort(sorted.begin(), sorted.end());
  sorted.resize(unique(sorted.begin(), sorted.end()) - sorted.begin());
  vector<int> result(values.size());
  for (int i = 0; i < values.size(); ++i) {
    result[i] =
        lower_bound(sorted.begin(), sorted.end(), values[i]) - sorted.begin();
  }
  return result;
}
int get_bit(long long mask, int bit) { return (int)((mask >> bit) & 1); }
long long set_bit(long long mask, int bit) { return mask | (1LL << bit); }
long long clear_bit(long long mask, int bit) { return mask & (~(1LL << bit)); }
string reverse(string s) {
  reverse(s.begin(), s.end());
  return s;
}
vector<int> reverse(vector<int> &a) {
  reverse(a.begin(), a.end());
  return a;
}
vector<int> concat_separated(vector<int> &a, vector<int> &b, int sep = -1) {
  size_t n = a.size(), m = b.size();
  vector<int> s(n + 1 + m);
  for (int i = 0; i < n; ++i) s[i] = a[i];
  s[n] = sep;
  for (int j = 0; j < m; ++j) s[n + 1 + j] = b[j];
  return s;
}
const int BASE = 1000 * 1000 * 1000 + 7;
const int MODULO = BASE;
template <long long modulo>
inline long long add(long long a, long long b) {
  return (a + b) % modulo;
}
template <long long modulo>
inline void add_to(long long &a, long long b) {
  a += b;
  if (a >= modulo) a -= modulo;
}
template <long long modulo>
inline long long subtract(long long a, long long b) {
  return add<modulo>(a, modulo - b);
}
template <long long modulo>
inline long long multiply(long long a, long long b) {
  return (int)((a * b) % modulo);
}
struct DSU {
  vector<int> parents;
  vector<int> sizes;
  vector<int> ranks;
  DSU(size_t n = 1) { resize(n); }
  void resize(size_t n) {
    parents.resize(n);
    for (int v = 0; v < n; ++v) {
      parents[v] = v;
    }
    ranks.resize(n, 1);
    sizes.resize(n, 0);
  }
  int get(int v) {
    int parent = parents[v];
    if (parent == v) return v;
    return parents[v] = get(parent);
  }
  bool merge(int f, int t, int weight = 1, bool multiple_edges = false) {
    int a = get(f);
    int b = get(t);
    if (multiple_edges) {
      sizes[a] += weight;
    }
    if (a == b) return false;
    if (ranks[a] < ranks[b]) {
      swap(a, b);
    }
    parents[b] = a;
    if (ranks[a] == ranks[b]) ++ranks[a];
    sizes[a] += sizes[b];
    if (!multiple_edges) sizes[a] += weight;
    return true;
  }
  bool connected(int f, int t) { return get(f) == get(t); }
  int get_size(int v) { return sizes[get(v)]; }
};
class SegmentTree {
 public:
  int size;
  vector<long long> t;
  SegmentTree(int n) : size(n), t(size << 2, 0) {}
  void update_vertex(int v, int vL, int vR) { t[v] = t[vL] + t[vR]; }
  int index;
  long long value;
  void update_value(int _index, long long _value) {
    index = _index;
    value = _value;
    update_tree_index(1, 0, size);
  }
  void update_tree_index(int v, int left, int right) {
    if (left + 1 == right) {
      t[v] = value;
    } else {
      int mid = (left + right) >> 1;
      int vL = (v << 1), vR = (vL + 1);
      if (index < mid)
        update_tree_index(vL, left, mid);
      else
        update_tree_index(vR, mid, right);
      update_vertex(v, vL, vR);
    }
  }
  int get_prefix(long long _value) {
    value = _value;
    return get_tree_prefix(1, 0, size);
  }
  int get_tree_prefix(int v, int left, int right) {
    if (left + 1 == right) {
      return left;
    } else {
      int mid = (left + right) >> 1;
      int vL = (v << 1), vR = (vL + 1);
      long long left_value = t[vL];
      if (left_value < value) {
        value -= left_value;
        return get_tree_prefix(vR, mid, right);
      } else {
        return get_tree_prefix(vL, left, mid);
      }
    }
  }
};
class FenwickTree {
  int size;
  vector<long long> t;
  vector<long long> values;

 public:
  FenwickTree(int n) : size(n + 1), t(size, 0LL), values(size, 0LL) {}
  void update_tree_index(int index, long long delta) {
    for (; index < size; index += index & -index) {
      t[index] += delta;
    }
  }
  void update_value(int index, long long value) {
    ++index;
    long long delta = value - values[index];
    values[index] = value;
    update_tree_index(index, delta);
  }
  long long _sum;
  int get_prefix(long long value) {
    int result = 0;
    _sum = 0;
    for (int bit = 20; bit >= 0; --bit) {
      int next = result | (1 << bit);
      if (next < size && _sum + t[next] < value) {
        result = next;
        _sum += t[next];
      }
    }
    return result;
  }
};
template <int block_size>
class SqrtDecomposition {
  int size;
  vector<long long> blocks;
  vector<long long> values;

 public:
  SqrtDecomposition(int n) : size(n), blocks(size, 0LL), values(size, 0LL) {}
  void update_index(int index, long long delta) {
    int block = index / block_size;
    blocks[block] += delta;
  }
  void update_value(int index, long long value) {
    long long delta = value - values[index];
    values[index] = value;
    update_index(index, delta);
  }
  long long sum;
  int get_prefix(long long value) {
    int result = 0;
    sum = 0;
    for (int block = 0; block * block_size < size; ++block) {
      long long next_sum = sum + blocks[block];
      if (next_sum < value) {
        sum = next_sum;
      } else {
        result = block * block_size;
        break;
      }
    }
    while (result < size && sum + values[result] < value) {
      sum += values[result];
      ++result;
    }
    return result;
  }
};
void update_max(int &cur_value, int new_value) {
  cur_value = max(cur_value, new_value);
}
void update_min(int &cur_value, int new_value) {
  cur_value = min(cur_value, new_value);
}
long long get_answer(vector<int> &);
vector<int> get_brute_answer(int n, int m,
                             vector<pair<int, int>> &friend_queries, int k,
                             vector<pair<int, int>> &edges, int q,
                             vector<vector<int>> &queries) {
  DSU dsu(n);
  map<int, vector<int>> friends;
  for (pair<int, int> &friend_query : friend_queries) {
    int f = friend_query.first - 1, t = friend_query.second - 1;
    friends[f].push_back(t);
    friends[t].push_back(f);
  }
  for (pair<int, int> &edge_query : edges) {
    int f = edge_query.first - 1, t = edge_query.second - 1;
    dsu.merge(f, t);
  }
  vector<int> answer;
  return answer;
}
FILE *print_file;
int print_test(int n, int m, vector<pair<int, int>> &friends, int k,
               vector<pair<int, int>> &edges, int q,
               vector<vector<int>> &queries, vector<int> &expected,
               vector<int> &actual, int bad_index) {
  fprintf(print_file, "%d %d %d\n", n, m, k);
  for (pair<int, int> &fq : friends) {
    fprintf(print_file, "%d %d\n", fq.first, fq.second);
  }
  for (pair<int, int> &eq : edges) {
    fprintf(print_file, "%d %d\n", eq.first, eq.second);
  }
  fprintf(print_file, "%d\n", q);
  fprintf(print_file, "===\n");
  for (int value : expected) {
    fprintf(print_file, "%d ", value);
  }
  fprintf(print_file, "\n");
  for (int value : actual) {
    fprintf(print_file, "%d ", value);
  }
  fprintf(print_file, "\n");
  fprintf(print_file, "%d\n", bad_index);
  fprintf(print_file, "===\n\n");
  return 1 + m + k + 1 + q + 1 + 1 + 1 + 1 + 1 + 1;
}
void set_print_file(const char *file_name) {
  print_file = fopen(file_name, "a");
}
void stress(int first_new_line = 1) {
  std::mt19937 rnd(time(0));
  std::uniform_int_distribution<> nGen(1, 10);
  int first_line = first_new_line;
  for (int it = 0; it < 100; ++it) {
    int n = nGen(rnd);
    long long expected = 0;
    long long actual = 0;
    if (expected != actual) {
      cout << "Gotcha!" << SPACE << first_line << endl;
      cout << expected << SPACE << actual << endl;
      return;
    }
  }
}
long long get_answer(vector<int> &a) {
  int n = a.size();
  vector<vector<int>> single_result_dp(n + 1, vector<int>(n + 1, -1));
  for (int i = 0; i < n; ++i) {
    single_result_dp[i + 1][i + 1] = a[i];
  }
  for (int length = 2; length <= n; ++length) {
    for (int left = 1, right = left + length - 1; right <= n; ++left, ++right) {
      for (int mid = left; mid < right; ++mid) {
        int left_res = single_result_dp[left][mid];
        int right_res = single_result_dp[mid + 1][right];
        if (left_res != -1 && left_res == right_res) {
          single_result_dp[left][right] = left_res + 1;
          break;
        }
      }
    }
  }
  vector<int> dp(n + 1, n + 1);
  dp[0] = 0;
  for (int i = 1; i <= n; ++i) {
    for (int prev = 0; prev < i; ++prev) {
      if (single_result_dp[prev + 1][i] != -1) {
        update_min(dp[i], dp[prev] + 1);
      }
    }
  }
  return dp[n];
}
int main() {
  ios::sync_with_stdio(false);
  cin.tie(nullptr);
  cout.tie(nullptr);
  int n = read_size();
  vector<int> a;
  read_vector(a, n);
  long long answer = get_answer(a);
  cout << answer << endl;
  return 0;
}
