CodeForces - 1312E Array Shrinking【区间DP】

题意

给定数组 a 1 , a 2 , . . . , a n a_1, a_2, ...,a_n a1,a2,...,an,你可以对该数组进行如下操作任意次数

  • 选择一对相邻且相等的数, a i = a i + 1 a_i = a_{i+1} ai=ai+1
  • a i + 1 a_i+1 ai+1代替这一对数

现在求数组经过几次操作后,可能的最短的长度。

1 ≤ n ≤ 500 , 1 ≤ a i ≤ 1000 1\le n \le500, 1\le a_i\le1000 1n500,1ai1000

5
4 3 2 2 3
2

7
3 3 4 4 4 3 3
2

3
1 3 5
3

1
1000
1

题解

  • 状态: d p [ i ] [ j ] dp[i][j] dp[i][j]表示在[i, j]范围内数组可能缩短的最短的长度
  • 额外一个数组 w [ i ] [ j ] w[i][j] w[i][j]表示如果[i,j]范围内可以缩短成长度为1的值,如果dp[i][j]不是1那w[i][j]就没有意义。该数组用于判断两段区间的合并
  • 状态转移: d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] + d p [ k + 1 ] [ j ] ) , k ∈ [ i , j ] dp[i][j] = min(dp[i][k] + dp[k+1][j]), k∈[i,j] dp[i][j]=min(dp[i][k]+dp[k+1][j]),k[i,j]
  • 如果有k使得 d p [ i ] [ k ] = = 1 ,   d p [ k + 1 ] [ j ] = = 1 ,   w [ i ] [ k ] = = w [ k + 1 ] [ j ] dp[i][k]==1, \ dp[k+1][j]==1, \ w[i][k]==w[k+1][j] dp[i][k]==1, dp[k+1][j]==1, w[i][k]==w[k+1][j]那么 d p [ i ] [ j ] = 2 dp[i][j]=2 dp[i][j]=2
#include<cstdio>
#include <iostream>
using namespace std;
#define ll long long
#define pr pair<int, int>
const int maxn=4000;

int n, m, ans;

int a[maxn];
int dp[maxn][maxn], val[maxn][maxn];

int main()
{
    cin >> n;
    for(int i=1;i<=n;i++){
        cin >> a[i];
        val[i][i] = a[i]; dp[i][i] = 1;
    }
    for(int i=n-1;i>0;i--)
    {
        for(int j=i+1;j<=n;j++)
        {
            dp[i][j] = 0x3f3f3f3f;
            for(int k=i;k<j;k++)
            {
                if(dp[i][k]+dp[k+1][j] < dp[i][j])
                {
                    dp[i][j] = dp[i][k] + dp[k+1][j];
                    if(val[i][k]==val[k+1][j] && dp[i][k] == dp[k+1][j] && dp[i][k] == 1)
                    {
                        val[i][j] = val[i][k] + 1;
                        dp[i][j] = 1;
                    }
                }
            }
        }
    }
    cout << dp[1][n] << endl;

    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值