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