题意:

有n个选手,每个人都有一个愤怒值a[i],当第i位选手是第k个出场的时候,他的愤怒值为(k-1)*a[i];

有一个黑箱子(堆栈),可以往里面放人(改变出场次序),问最小的愤怒值。

解析:

dp[i][j]保存的是i到j之间最大的愤怒值减小量。

假设第i个人第k个上场,那么后面第i+1到第K个人就会都提前一名上场,第K个人到第J个人愤怒值不变。

也就是dp[i][j]=min(a[i]*(k-1)+sum[i]-sum[k]+dp[i+1][k]+dp[k+1][j]);

最后输出原始值+减小量即可

附上ac代码:

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <vector>
#include <cstdio>
using namespace std;
#define N 105
int a[N],sum[N],dp[N][N];
int main()
{
    //freopen("in.txt","r",stdin);
    int t;
    scanf("%d",&t);
    for(int y=1;y<=t;y++)
    {
        int n,ans=0;
        scanf("%d",&n);
        sum[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            sum[i]=sum[i-1]+a[i];
            ans=ans+a[i]*(i-1);
        }
        memset(dp,0,sizeof(dp));
        for(int i=1;i<n;i++)
            dp[i][i+1]=min(dp[i][i+1],a[i]-a[i+1]);
        for(int l=2;l<n;l++)
        {
            for(int i=1;i+l<=n;i++)
            {
                int j=i+l;
                for(int k=i;k<=j;k++)
                    dp[i][j]=min(dp[i][j],a[i]*(k-i)-sum[k]+sum[i]+dp[i+1][k]+dp[k+1][j]);
            }
        }
        printf("Case #%d: %d\n",y,ans+dp[1][n]);
    }
    return 0;
}