Wannafly Winter Camp 2020 Day 6I 变大!

给定一个序列,可以执行 (k) 次操作,每次选择连续的三个位置,将他们都变成他们的最大值,最大化 (sum a_i)

需要对每一个 (k=i) 输出答案

(n leq 50, a_i leq 20),数据组数 (leq 100)

Solution

我们考虑将这些数分段,每段刷成区间内的最大值,那么很显然就可以 DP 了

(f[i][j]) 表示搞定了前 (i) 个数,操作了 (j) 次,则转移方程

[f[i][j]=max_k (f[k][j-frac{i-k}{2}]+m[k+1][i]cdot (i-k)) ]

其中 (m[l][r]) 表示 ([l,r]) 这段区间的最大值,可以暴力预处理得到

总体时间复杂度 (O(Tn^3))

#include <bits/stdc++.h>
using namespace std;

#define int long long
const int N = 105;
int t,n,a[N],f[N][N],m[N][N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>t;
    while(t--) {
        cin>>n;
        for(int i=1;i<=n;i++) cin>>a[i];
        memset(f,0,sizeof f);
        memset(m,0,sizeof m);
        for(int i=1;i<=n;i++) {
            for(int j=i;j<=n;j++) {
                for(int k=i;k<=j;k++) {
                    m[i][j]=max(m[i][j],a[k]);
                }
            }
        }
        memset(f,-0x3f,sizeof f);
        f[0][0]=1;
        for(int i=1;i<=n;i++) {
            for(int j=0;j<=n;j++) {
                if(j>0) f[i][j]=f[i][j-1];
                for(int k=0;k<i;k++) {
                    if(j>=(i-k)/2 && k!=i-2)
                        f[i][j]=max(f[i][j],
                            f[k][j-(i-k)/2]+m[k+1][i]*(i-k));
                }
            }
        }
        for(int i=1;i<=n;i++) {
            cout<<f[n][i]-1<<(i==n?"
":" ");
        }
    }
}

原文地址:https://www.cnblogs.com/mollnn/p/12367442.html