codeforces 1312E. Array Shrinking(区间dp)

codeforces 1312E. Array Shrinking

题意:

相同的两个\(x\)可以合并成\(x+1\),给一个序列,问最后数组中最少能剩下多少个数。

思路:

数据500,很明显的区间dp数据。
考虑之前区间\(sum[1] [j]\)表示\(i,j\)合并以后能得到一个\(k\),如果\(k=0\),表示不能合并到一起。
先预处理\(sum[i][j]\)的元素个数为\(j-i+1\)\(sum[i][i]=a[i]\)
然后就是常规区间dp了,枚举区间长度,区间起点和区间终点。
只有当左区间和右区间的长度为1且左右区间各自合并出来的数字相等时才可以合并,即\(sum[i][k]==dp[k+1][j]\&\&sum[i][k]>0\)

最后更新dp。

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn = 510;
int a[maxn], dp[maxn], sum[maxn][maxn];
void solve(){
    int n;
    cin >> n;
    for (int i = 1; i <= n; i++){
        cin >> a[i];
        sum[i][i] = a[i];
    }
    for (int len = 1; len <= n; len++){
        for (int i = 1; i <= n - len; i++){
            int j = len + i;
            for (int k = i; k < j; k++){
                if(sum[i][k] == sum[k+1][j] && sum[i][k] != 0){
                    sum[i][j] = sum[i][k] + 1;
                }
            }
        }
    }
    dp[0] = 0;
    for (int i = 1; i <= n; i++){
        dp[i] = dp[i - 1] + 1;
        for (int j = 1; j <= i; j++){
            if(sum[j][i] > 0){
                dp[i] = min(dp[i], dp[j - 1] + 1);
            }
        }
    }
    cout << dp[n] << endl;
}
int main(){
    ios_base::sync_with_stdio(0);
    solve();
    return 0;
}
posted @ 2020-03-18 22:04  Frnas  阅读(172)  评论(0编辑  收藏  举报
Language: HTML