- f[j][end]=min(f[j][end],f[j][k]+f[k+1][end]+sum(j,end));
- g[j][end]=max(g[j][end],g[j][k]+g[k+1][end]+sum(j,end));
- #include<iostream>
- #include<cstring>
- using namespace std;
- int n,a[301],Prefix[200],end,f[205][205],g[205][205],maxn,minn=21370444;
//Prefix前缀和,只需要进行线性的预处理,即可享受常数的求和方法(手动滑稽)(蒟蒻英语不好,上网百度的) - int sum(int i,int j)//求第i堆到第j堆的和
- {
- return Prefix[j]-Prefix[i-1];
- }
- int main()
- {
- memset(f,20,sizeof(f));//初始化
- cin>>n;
- for(int i=1;i<=n;i++)
- {
- cin>>a[i];
- a[i+n]=a[i];//构造更长的链
- }
- for(int i=1;i<=n*2;i++)
- {
- Prefix[i]=a[i]+Prefix[i-1];//打前缀和
- f[i][i]=0;//自己和自己合并不需要花费
- g[i][i]=0;
- }
- for(int i=2;i<=n;i++)
- {
- for(int j=1;j<=2*n-i+1;j++)//j表示合并的左端点
- {
- end=i+j-1;//end表示合并的右端点
- for(int k=j;k<end;k++)//枚举断点
- {
- f[j][end]=min(f[j][end],f[j][k]+f[k+1][end]+sum(j,end));
- g[j][end]=max(g[j][end],g[j][k]+g[k+1][end]+sum(j,end));
- }
- }
- }
- for(int i=1;i<=n;i++)//打擂台求最大最小
- {
- maxn=max(g[i][i+n-1],maxn);
- minn=min(f[i][i+n-1],minn);
- }
- cout<<minn<<endl<<maxn<<endl;
- return 0;//终于结束了。。。
- }