#include<iostream>
#include<stdio.h>
#include<cstring>
#define INF 0x7fffffff
using namespace std;
const int m=2100;
int dp[m][m];///定义在区间(i,j)内的最优值
int o[m][m];
int stone[m];
int sum[m];///定义前缀和,用来求,2个堆这一次的合并值
int main()
{
int n;
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>stone[i];
stone[i+n]=stone[i];
}
sum[0]=0;
for(int i=1;i<=2*n-1;i++)
{
sum[i]=sum[i-1]+stone[i];
dp[i][i]=0;
o[i][i]=i;
}
for(int l=2;l<=n;l++)///区间长度
{
int e=2*n-1;
for(int s=1;s+l-1<=2*n-1;s++)///起点 正向,反向都可以 ,因为是小区间到大区间,不影响
{
dp[s][s+l-1]=0x7fffffff;///没过可能是因为不够大
for(int k=o[s][s+l-2];k<=o[s+1][s+l-1]&&k+1<=s+l-1;k++)///定理 OI WIKI上
{
if(dp[s][s+l-1]>dp[s][k]+dp[k+1][s+l-1]+sum[s+l-1]-sum[s-1])
{
dp[s][s+l-1]=dp[s][k]+dp[k+1][s+l-1]+sum[s+l-1]-sum[s-1];
o[s][s+l-1]=k;
}
}
}
}
int Min=0x7fffffff;
for(int i=1;i+n-1<=2*n-1;i++)
Min=min(Min,dp[i][i+n-1]);
cout<<Min<<endl;
return 0;
}
石子归并 V2 51Nod - 1022
最新推荐文章于 2024-11-08 11:06:20 发布