4457: 【入门】石子合并(环形)(2058)

内存限制:128 MB 时间限制:1.000 S
评测方式:文本比较 命题人:
提交:3 解决:2

题目描述

在一个圆形操场的四周摆放 lns="http://www.w3.org/1998/Math/MathML"> 堆石子,现要将石子有次序地合并成一堆。规定每次只能选相邻的 lns="http://www.w3.org/1998/Math/MathML">2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 lns="http://www.w3.org/1998/Math/MathML"> 堆石子合并成 lns="http://www.w3.org/1998/Math/MathML">1 堆的最小得分和最大得分。

输入

数据的第 lns="http://www.w3.org/1998/Math/MathML">1 行是正整数 lns="http://www.w3.org/1998/Math/MathML">,表示有 lns="http://www.w3.org/1998/Math/MathML"> 堆石子。

第 lns="http://www.w3.org/1998/Math/MathML">2 行有 lns="http://www.w3.org/1998/Math/MathML"> 个整数,第 lns="http://www.w3.org/1998/Math/MathML"> 个整数 lns="http://www.w3.org/1998/Math/MathML"> 表示第 lns="http://www.w3.org/1998/Math/MathML"> 堆石子的个数。

lns="http://www.w3.org/1998/Math/MathML">1400020

输出

输出共 lns="http://www.w3.org/1998/Math/MathML">2 行,第 lns="http://www.w3.org/1998/Math/MathML">1 行为最小得分,第 lns="http://www.w3.org/1998/Math/MathML">2 行为最大得分。

样例输入 复制

4
4 5 9 4

样例输出 复制

43
54

提示

#include<bits/stdc++.h>
using namespace std;
/* 
将数据规模翻倍,将a数组完整接贝一遍求
区间最长长度为的情况下,合并得到的最优解
再从每个可能的起点出发,打播台求最小、最大值
*/ 
const int N= 410;
int a[N*2],s[N*2]; //s:前缀和
int mi[N*2][N*2],ma[N*2][N*2];
int n;
int main(){
    cin>>n; //初始化
    memset(mi,0x3f,sizeof(mi));
    memset(ma,-0x3f,sizeof(ma));
    for(int i= 1;i<= n;i++){
        cin>>a[i];
        a[i+n]= a[i]; //数组完整的赋值一遍
    }
    for(int i=1;i<= n*2;i++) {
	    s[i]=s[i-1]+a[i];
	    mi[i][i]= 0;
	    ma[i][i]= 0;
    }
	//初始化
    //区间dp求解
    //穷举所有可能的区间长度
    for(int len=2;len<= n;len++){ 
        //穷举区间的左端点
        for(int i=1;i+len-1<= n* 2;i++){ 
            //右端点
            int j=i+len-1; 
            //穷举分割点
            for(int k= i;k< j;k++){
                mi[i][j]=min(mi[i][j],mi[i][k]+mi[k+1][j]+s[j]-s[i-1]);
                ma[i][j]=max(ma[i][j],ma[i][k]+ma[k+1][j]+s[j]-s[i-1]);
            }
        }
    }
    //穷举所有可能的出发点,打擂台求最小、最大
    int minn = INT_MAX,maxn = INT_MIN; 
    for(int i= 1;i<= n;i++){
        minn = min(minn,mi[i][i+n-1]);
        maxn = max(maxn,ma[i][i+n-1]);
    }
    cout<<minn<<endl<<maxn;
    return 0;
}