dp[i][j]表示区间[i,j]的最小总不开心值

把区间[i,j]单独来看,则第i个人可以是第一个出场,也可以是最后一个出场,也可以是在中间出场,总之就是在【1,  j-i+1】出场


设他是第k个出场的(1<=k<=j-i+1),那么:

【i+1 ,i+k-1】内总共有k-1个人要比i先出栈;

【 i+k ,j】内 总共j-i-k+1个人在i后面出栈


举个例子:

有5个人事先排好顺序  1,2,3,4,5

入栈的时候,1入完2入,2入完3入,如果我要第1个人第3个出场,那么入栈出栈顺序是这样的:

1入,2入,3入,3出,2出,1出(到此第一个人就是第3个出场啦,很明显第2,3号人要在1先出,而4,5要在1后出)


故可定义状态转移方程:

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

在i+1之后的K-1个人是率先上场的,那么就出现了一个子问题 dp[i+1][i+k-1]表示在第i个人之前上场的 

对于第i个人,由于是第k个上场的,那么不开心值便是a[i]*(k-1) 

其余的人是排在第k+1个之后出场的,也就是一个子问题dp[i+k][j],对于这个区间的人,由于排在第k+1个之后,所以整体愤怒值要加上k*(sum[j]-sum[i+k-1])

(sum[j]-sum[i+k-1])*k 表示 后面的 j-i-k+1个人是在i后面才出场的,那么每个人的不开心值都会加个 unhappy,sum[i]用来记录前面i个人的总不开心值,根据题目,每个人的unhappy是个 累加的过程 ,多等一个人,就多累加一次

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int INF = 0x3f3f3f3f;
int dp[110][110], sum[110], a[110], n;

int main()
{
int T; scanf("%d", &T);
for (int kase = 1; kase <= T; kase++) {
scanf("%d", &n);
sum[0] = 0;
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 len = 1; len <= n; len++) {//先解决长度小的子问题
for (int i = 1; i <= n - len + 1; i++) {
int j = i + len - 1;
for (int k = 1; k <= len; k++) {
dp[i][j] = min(dp[i][j], dp[i + 1][i + k - 1] + dp[i + k][j] + (k - 1) * a[i] + (sum[j] - sum[i + k - 1]) * k);
}
}
}
printf("Case #%d: %d\n", kase, dp[1][n]);
}
return 0;
}


样例怎么粘程序都跑不起来,自己手打可以运行,不知怎么回事,好在交上后过了