P1880 [NOI1995] 石子合并(区间dp)

P1880 [NOI1995] 石子合并

题目描述

在一个圆形操场的四周摆放 N 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 2 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。

试设计出一个算法,计算出将 N 堆石子合并成 1 堆的最小得分和最大得分。

输入格式

数据的第 1 行是正整数 N,表示有 N 堆石子。

2 行有 N 个整数,第 i 个整数 ai 表示第 i 堆石子的个数。

输出格式

输出共 2 行,第 1 行为最小得分,第 2 行为最大得分。

输入输出样例 #1

输入 #1

4
4 5 9 4

输出 #1

43
54

说明/提示

1N1000ai20
由于这道题石子是环形,我们可以开两倍的数组,然后循环列举起点,然后分别计算最大值和最小值

#include<iostream>
#include<cstring>
using namespace std;
const int N=500+5;
int s[N];
int Max[N][N];
int Min[N][N];
int MAX=-1;
int MIN=1e9;
int main(){
    int n;
    cin>>n;
    memset(Max,-0x3f,sizeof(Max));
    memset(Min,0x3f,sizeof(Min));
    for(int i=1;i<=n;i++){
        cin>>s[i];
        s[i+n]=s[i];
        Max[i][i]=0;
        Max[i+n][i+n]=0;
        Min[i][i]=0;
        Min[i+n][i+n]=0;
    }
    for(int i=1;i<=2*n;i++)s[i]+=s[i-1];
    for(int i=1;i<=n;i++){
        for(int len=2;len<=n;len++){
            for(int l=i;l+len-1<=n+i-1;l++){
                int r=l+len-1;
                for(int k=l;k<r;k++){
                    Max[l][r]=max(Max[l][r],Max[l][k]+Max[k+1][r]+s[r]-s[l-1]);
                    Min[l][r]=min(Min[l][r],Min[l][k]+Min[k+1][r]+s[r]-s[l-1]);
                }
               
            }
        }
        MAX=max(MAX,Max[i][n+i-1]);
        MIN=min(MIN,Min[i][n+i-1]);
    }
    cout<<MIN<<endl<<MAX;
    return 0;
}
posted @   郭轩均  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
点击右上角即可分享
微信分享提示