「ダイナミックプログラミングの最適化。」

<>はい

<第更新>


<テキスト>

最適化

説明

\(\ _worldの\を訪問)、いくつかの最適化問題は非常に通常の技術によって解決することができたので、彼はあなたがそのような質問を共有しました:

今整数Nの系列長有する(\ {a_iを\} \)\を彼らが覚えているように、あなたは互いに素K連続サブ間隔を選択する必要がある(存在する元素から選択することができない)、そして左から右へ\(S1、S2、...、SK \) 私たちの目標は、以下の式を最適化し、最大化することです。

\ [\ sum_ {i = 1} ^ K | S_I-S_ {I + 1} | \]

あなただけの最大出力を必要とすることができます。

入力形式

二つの整数N、Kの最初の行は、上記のように意味します。

次の行Nの整数、確実に、i番目のAIを表し\(| a_iを|≦10 4 ^を\)

出力フォーマット

出力ラインの答えを表す整数。

サンプル入力

5 3
5 2 4 3 1

サンプル出力

12

解決

非常に不思議な\(DP \)

絶対最大値と、少しについて\(トリック\)の両方の場合において、オープン正および負の数の絶対値である(DPの\)\、そして最終的には一定の最大値に最適な解決策です。

那么我们发现对于一个\(s_i\),他可能有三种贡献系数:\(2,-2,0\),这与\(s_{i-1},s_{i+1}\)与其的相对大小关系有关,当然,对于\(s_1,s_k\),他们的贡献系数还有可能是\(1,-1\),我们不妨由此设计状态。

\(f[i][j][0/1/2/3]\)代表前\(i\)个数,分成\(j\)段,当前处于最大值(\(+2\)贡献),最小值(\(-2\)贡献),上升状态(\(0\)贡献),下降状态(\(0\)贡献)的最大和。其中上升状态和下降状态指的就是最大值和最小值前的一些\(0\)贡献的状态。

然后就可以\(dp\)了,时间复杂度是\(O(n^3k)\)的。

考虑优化,第一个就是我们可以强制认为每一个数字都是要取的,当然不取可以放在\(0\)贡献的状态里处理。第二个每一段当中的数字贡献系数的相同的,可以直接一个一个添加数字。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 3e4+20 , K = 220 , INF = 0x3f3f3f3f;
inline int read(void)
{
    int x = 0 , w = 0; char ch = ' ';
    while ( !isdigit(ch) ) w |= ch == '-' , ch = getchar();
    while ( isdigit(ch) ) x = x * 10 + ch - 48 , ch = getchar();
    return w ? -x : x;
}
int n,k,a[N],f[N][K][4];
inline void input(void)
{
    n = read() , k = read();
    for (int i=1;i<=n;i++)
        a[i] = read();
}
inline void dp(void)
{
    memset( f , 0xcf , sizeof f );
    for (int i=1;i<=n;i++)
        f[i][0][0] = f[i][0][1] = f[i][0][2] = f[i][0][3] = 0;
    f[0][0][0] = f[0][0][1] = f[0][0][2] = f[0][0][3] = 0;
    for (int i=1;i<=n;i++)
        for (int j=1;j<=min(i,k);j++)
        {
            int mul = 2;
            if ( j == 1 || j == k ) mul--;
            f[i][j][0] = max( f[i-1][j][0] , f[i-1][j-1][2] ) + mul * a[i];
            f[i][j][1] = max( f[i-1][j][1] , f[i-1][j-1][3] ) - mul * a[i];
            f[i][j][2] = max( f[i-1][j][2] , f[i][j][1] );
            f[i][j][3] = max( f[i-1][j][3] , f[i][j][0] );
            if ( mul == 1 ) continue;
            f[i][j][2] = max( f[i][j][2] , f[i-1][j-1][2] );
            f[i][j][3] = max( f[i][j][3] , f[i-1][j-1][3] );
        }
}
int main(void)
{
    input();
    dp();
    printf("%d\n",max(f[n][k][2],f[n][k][3]));
    return 0;
}

<后记>

おすすめ

転載: www.cnblogs.com/Parsnip/p/11415003.html