P1880 [NOI1995] 石子合并(区间dp)
P1880 [NOI1995] 石子合并
题目描述
在一个圆形操场的四周摆放 \(N\) 堆石子,现要将石子有次序地合并成一堆,规定每次只能选相邻的 \(2\) 堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出一个算法,计算出将 \(N\) 堆石子合并成 \(1\) 堆的最小得分和最大得分。
输入格式
数据的第 \(1\) 行是正整数 \(N\),表示有 \(N\) 堆石子。
第 \(2\) 行有 \(N\) 个整数,第 \(i\) 个整数 \(a_i\) 表示第 \(i\) 堆石子的个数。
输出格式
输出共 \(2\) 行,第 \(1\) 行为最小得分,第 \(2\) 行为最大得分。
输入输出样例 #1
输入 #1
4
4 5 9 4
输出 #1
43
54
说明/提示
\(1\leq N\leq 100\),\(0\leq a_i\leq 20\)。
由于这道题石子是环形,我们可以开两倍的数组,然后循环列举起点,然后分别计算最大值和最小值
#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;
}

浙公网安备 33010602011771号