[Educational Codeforces Round 83 ] E. Array Shrinking - (区间DP)

E. Array Shrinking

time limit per test

2 seconds

memory limit per test

256 megabytes

input

standard input

output

standard output

You are given an array a1,a2,…,ana1,a2,…,an. You can perform the following operation any number of times:

  • Choose a pair of two neighboring equal elements ai=ai+1ai=ai+1 (if there is at least one such pair).
  • Replace them by one element with value ai+1ai+1.

After each such operation, the length of the array will decrease by one (and elements are renumerated accordingly). What is the minimum possible length of the array aa you can get?

Input

The first line contains the single integer nn (1≤n≤5001≤n≤500) — the initial length of the array aa.

The second line contains nn integers a1,a2,…,ana1,a2,…,an (1≤ai≤10001≤ai≤1000) — the initial array aa.

Output

Print the only integer — the minimum possible length you can get after performing the operation described above any number of times.

Examples

input

Copy

5
4 3 2 2 3

output

Copy

2

input

Copy

7
3 3 4 4 4 3 3

output

Copy

2

input

Copy

3
1 3 5

output

Copy

3

input

Copy

1
1000

output

Copy

1

Note

In the first test, this is one of the optimal sequences of operations: 44 33 22 22 33 →→ 44 33 33 33 →→ 44 44 33 →→ 55 33.

In the second test, this is one of the optimal sequences of operations: 33 33 44 44 44 33 33 →→ 44 44 44 44 33 33 →→ 44 44 44 44 44 →→ 55 44 44 44 →→ 55 55 44 →→ 66 44.

In the third and fourth tests, you can't perform the operation at all.

题意:

给定一个含有n个整数的数组,你可以将两个相邻且相等的数\(X\)合并成一个\(X+1\),其他的数位置和数值都不变,问当你在最优操作的情况下,最少能剩下多少个元素?

思路:

数据范围考虑用区间DP,

定义状态:\(dp[i][j]\)表示数组\(a_i,a_{i+1},\dots,a_{j}\) 可以合并的最短长度。

辅助数组:\(b[i][j]\)表示数组\(a_i,a_{i+1},\dots,a_{j}\) 可以合并的最短长度时的数值。

转移:

不合并时:

枚举区间\([i,j]\)中的k,\(dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j])\)

合并元素时:

\(dp[i][k] = 1 , dp[k + 1][j] = 1 , b[i][k] = b[k + 1][j]\)\(dp[i][j] = 1,b[i][j] = b[i][k] + 1\)

代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <iomanip>
#include <sstream>
#include <bitset>
#define ALL(x) (x).begin(), (x).end()
#define sz(a) int(a.size())
#define rep(i,x,n) for(int i=x;i<n;i++)
#define repd(i,x,n) for(int i=x;i<=n;i++)
#define pii pair<int,int>
#define pll pair<long long ,long long>
#define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define MS0(X) memset((X), 0, sizeof((X)))
#define MSC0(X) memset((X), '\0', sizeof((X)))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define eps 1e-6
#define chu(x) cout<<"["<<#x<<" "<<(x)<<"]"<<endl
#define du3(a,b,c) scanf("%d %d %d",&(a),&(b),&(c))
#define du2(a,b) scanf("%d %d",&(a),&(b))
#define du1(a) scanf("%d",&(a));
using namespace std;
typedef long long ll;
ll gcd(ll a, ll b) {return b ? gcd(b, a % b) : a;}
ll lcm(ll a, ll b) {return a / gcd(a, b) * b;}
ll powmod(ll a, ll b, ll MOD) { if (a == 0ll) {return 0ll;} a %= MOD; ll ans = 1; while (b) {if (b & 1) {ans = ans * a % MOD;} a = a * a % MOD; b >>= 1;} return ans;}
ll poww(ll a, ll b) { if (a == 0ll) {return 0ll;} ll ans = 1; while (b) {if (b & 1) {ans = ans * a ;} a = a * a ; b >>= 1;} return ans;}
void Pv(const vector<int> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%d", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
void Pvl(const vector<ll> &V) {int Len = sz(V); for (int i = 0; i < Len; ++i) {printf("%lld", V[i] ); if (i != Len - 1) {printf(" ");} else {printf("\n");}}}
inline long long readll() {long long tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
inline int readint() {int tmp = 0, fh = 1; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') fh = -1; c = getchar();} while (c >= '0' && c <= '9') tmp = tmp * 10 + c - 48, c = getchar(); return tmp * fh;}
const int maxn = 510;
const int inf = 0x3f3f3f3f;
/*** TEMPLATE CODE * * STARTS HERE ***/
int n;
int a[maxn];
int b[maxn][maxn];
int dp[maxn][maxn];
int main()
{
    //freopen("D:\\code\\text\\input.txt","r",stdin);
    //freopen("D:\\code\\text\\output.txt","w",stdout);
    n = readint();
    repd(i, 1, n)
    {
        a[i] = readint();
        b[i][i] = a[i];
    }
    repd(i, 1, n)
    {
        repd(j, i, n)
        {
            dp[i][j] = j - i + 1;
        }
    }
    repd(len, 2, n)
    {
        repd(i, 1, n - len + 1)
        {
            int j = i + len - 1;
            repd(k, i, i + len - 2)
            {
                dp[i][j] = min(dp[i][j], dp[i][k] + dp[k + 1][j]);
                if (dp[i][k] == 1 && dp[k + 1][j] == 1 && (b[i][k] == b[k + 1][j]))
                {
                    dp[i][j] = 1;
                    b[i][j] = b[i][k] + 1;
                }
            }
        }
    }
    printf("%d\n", dp[1][n] );
    return 0;
}