codeforces 1312E. Array Shrinking

题意:

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

思路:

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