开始读题读了半天,还是参考了大佬的博客
https://blog.csdn.net/codeswarrior/article/details/81479291
有一群屌丝,每个屌丝有个屌丝值,如果他第K个上场,屌丝值就为a[i]*(k-1),因为前面有k-1个人在他前面上台,可以把几个人拉进小黑屋来调整,可以把小黑屋当成栈因为先进去的人最后才能出来,使得最后总屌丝值最小
//定义dp[i][j]表示原序列区间[i,j]的人的最小屌丝值
//枚举一个中间变量k,设i在区间[i,j]中是第k个上场的
//这样区间分成了两部分
//dp[i+1][i+k-1](k-1个人在i之前),dp[i+k][j](之后的人)
//也就是让[i,i+k-1]这些人进入小黑屋
//i先进的,那么他前面将有k-1个人
//他是第k个上场的,之后再让后面的[i+k,j]这些人上场
//这样很明显i等待了k-1个人屌丝值增长为(k-1)×a[i],而[i+k,j]这些人则等待了k个人,屌丝值增长为k×(这些人的屌丝值之和)
//因此状态转移公式为
//dp[i][j]=min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+k×(sum[j]-sum[i+k-1])+a[i]×(k-1))
//sum[]记录了每个人屌丝值的前缀和
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = 0x3f3f3f3f;
int n,a[105],sum[105],dp[105][105];
int main() {
int t,cas = 0;
scanf("%d",&t);
while(t--) {
scanf("%d",&n);
memset(sum,0,sizeof(sum));
for(int i = 1; i <= n; i++) {
scanf("%d",&a[i]);
sum[i] = sum[i-1] + a[i];
}
memset(dp,0,sizeof(dp));
for(int i = 1; i <= n; i++) {
for(int j = i + 1; j <= n; j++) {
dp[i][j] = INF;
}
}
//区间长度
for(int l = 1; l < n; l++)
//左端点, 右端点
for(int i = 1; i + l <= n; i++) {
//右端点
int j = i + l;
//枚举中间量,第几个上场
for(int k = 1; k <= j - i + 1; k++)
dp[i][j] = min(dp[i][j],dp[i+1][i+k-1]+dp[i+k][j]+k*(sum[j]-sum[i+k-1])+a[i]*(k-1));
}
printf("Case #%d: %d
",++cas,dp[1][n]);
}
return 0;
}