#include <bits/stdc++.h>
using namespace std;
/*
【题目描述】
在一个操场上一排地摆放着N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
计算出将N堆石子合并成一堆的最小得分。
【输入】
第一行为一个正整数N (2≤N≤100);
以下N行,每行一个正整数,小于10000,分别表示第i堆石子的个数(1≤i≤N)。
【输出】
一个正整数,即最小得分。
【输入样例】
7
13
7
8
16
21
4
18
【输出样例】
239
【提示】
无
【重点】
·现要将石子有次序地合并成一堆
·每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分
·计算出将N堆石子合并成一堆的最小得分
·一行为一个正整数N (2≤N≤100)
·以下N行,每行一个正整数,小于10000,分别表示第i堆石子的个数(1≤i≤N)
·一个正整数,即最小得分
【类型】
动态规划(区间动态规划)
【状态转移方程】
dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r] + s[r] - s[l - 1]);
【附件】
区间动态规划的模板:
for (int len = 1; len <= n; len++)
for (int j = 1; j + len - 1 <= n; j++)
{
int ends = j + len - 1;
for (int i = j; j < ends; i++)
dp[j][ends] = min(dp[j][ends], dp[j][i] + dp[i + 1][ends] + ...);
}
*/
const int maxn = 5005;
const int INF = 0x3f3f3f3f;
int num[maxn], s[maxn];
int dp[maxn][maxn];
int n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> num[i];
s[i] = s[i - 1] + num[i];
}
for (int len = 2; len <= n; len++)
for (int i = 1; i + len - 1 <= n; i++)
{
int l = i, r = len + i - 1;
dp[l][r] = INF;
for (int k = l; k < r; k++)
dp[l][r] = min(dp[l][r], dp[l][k] + dp[k + 1][r] + s[r] - s[l - 1]);
}
cout << dp[1][n];
return 0;
}