给定一个序列,可以执行 \(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?"\n":" ");
        }
    }
}

相关文章:

  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2022-12-23
  • 2022-12-23
  • 2021-06-05
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
  • 2022-12-23
相关资源
相似解决方案