CodeForces - 1312Eアレイは【区间DP】縮小

問題の意味

配列を指定して、 A 1 A 2 A n個 A_1、A_2、...、A_N あなたは配列に次の操作を行うことができ、任意の回数

  • 対選択隣接のをとが等しい a i = a i + 1 a_iを= A_ {I + 1}
  • 使用 a i + 1 a_iを+ 1 の代わりに、対数の

複数のアレイ後今、可能な限り最短の長さをシーク。

1 n 500 , 1 a i 1000 1 \ K \ le500、1 \ a_iを\ le1000

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] [I、J]アレイが最短長さの範囲を減少させることができる表し
  • 追加の配列 w [ i ] [ j ] W [i]は[J] 示す1の値の範囲の長さを短くすることができる[I、J]場合DP [I] [j]はW [i] [j]は意味を成さないことではない場合には、。2つの配列セクションをマージする決意
  • 状態遷移: d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] + d p [ k + 1 ] [ j ] ) , k [ i , j ] DP [I] [J] =分(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] まあ d p [ 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;
}
公開された40元の記事 ウォン称賛15 ビュー1802

おすすめ

転載: blog.csdn.net/irimsky/article/details/104842428