[lnsyoj2239/luoguP5336/THUSC2016]成绩单

题意

给定序列 \(W\) 及常数 \(a,b\),对其进行删除操作,每次可以删除相邻的一段 \([L,R]\),然后原序列中的 \(L-1\)\(R+1\) 拼合起来,视为相邻。记共操作 \(k\) 次,每次操作中,该段的最大值为 \(mx_i\),最小值为 \(mn_i\),求

\[a \times k + b \times \sum_{i = 1} ^ k (mx_i - mn_i) ^ 2 \]

的最小值。

赛时 10PTS

赛后

本题需要处理相邻段问题,因此可以用 DP 解决。
\(f_{l,r}\) 表示将 \([L,R]\) 删完后的最小值。由于存在拼合这样的变态要求,因而无法直接解决。我们继续考虑,可以记录将 \([L,R]\) 删完的前一步 \(g\)。由于代价只与 \(mx\)\(mn\) 有关,因此我们记录四维数组 \(g_{l,r,mn,mx}\) 表示 \([L,R]\) 删完之前,剩余的元素中最大值为 \(mx\),最小值为 \(mn\) 的最终结果的最小值。因此就有:

\[f_{l,r} = \min\{g_{l,r,mn,mx} + a + b \times (mx-mn)^2\} \]

我们考虑 \(g\),当将 \(r\) 向右移动一位时,我们发现有两种情况:

  1. 在最后一步时才删除 \(W_r\)
  2. 在最后一步之前删除 \(W_r\)

若为情况 \(1\),则我们需要进行刷表转移,即:

\[g_{l,r + 1,\min\{mn,W_{r+1}\},\max\{mx,W_{r+1}\}}=\min\{g_{l,r + 1,\min\{mn,W_{r+1}\},\max\{mx,W_{r+1}\}},g_{l,r,mn,mx}\} \]

否则,我们进行填表转移,此时我们需要枚举一个断点 \(t\),使得 \((t, r]\) 被一起删除,即:

\[g_{l,r,mn,mx}=\min_{i=l}^{r-1}\{g_{l,t,mn,mx}+f_{t+1,r}\} \]

由于 \(w\) 范围较大,因此需要离散化。

代码

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>

using namespace std;

const int N = 55;

vector<int> ha;
int f[N][N], g[N][N][N][N];
int n, a, b, w[N];

int main(){
    scanf("%d%d%d", &n, &a, &b);
    for (int i = 1; i <= n; i ++ ) scanf("%d", &w[i]), ha.push_back(w[i]);
    sort(ha.begin(), ha.end());
    ha.erase(unique(ha.begin(), ha.end()), ha.end());
    for (int i = 1; i <= n; i ++ ) 
        for (int j = 0; j < ha.size(); j ++ )
            if (w[i] == ha[j]){
                w[i] = j;
                break;
            }

    memset(f, 0x3f, sizeof f), memset(g, 0x3f, sizeof g);
    for (int i = 1; i <= n; i ++ ) g[i][i][w[i]][w[i]] = 0;

    for (int len = 1; len <= n; len ++ ){
        for (int l = 1; l + len - 1 <= n; l ++ ){
            int r = l + len - 1;
            for (int mn = 0; mn < ha.size(); mn ++ ){
                for (int mx = 0; mx < ha.size(); mx ++ ){
                    for (int t = l; t < r; t ++ ){
                        g[l][r][mn][mx] = min(g[l][r][mn][mx], g[l][t][mn][mx] + f[t + 1][r]);
                    }
                    g[l][r + 1][min(mn, w[r + 1])][max(mx, w[r + 1])] = min(g[l][r + 1][min(mn, w[r + 1])][max(mx, w[r + 1])], g[l][r][mn][mx]);
                    f[l][r] = min(f[l][r], g[l][r][mn][mx] + a + b * (ha[mx] - ha[mn]) * (ha[mx] - ha[mn]));
                }
            }
        }
    }

    printf("%d\n", f[1][n]);

    return 0;
}
posted @ 2024-08-07 17:15  是一只小蒟蒻呀  阅读(12)  评论(0编辑  收藏  举报