【洛谷 1880】石子合并
题目描述
在一个圆形操场的四周摆放N堆石子,现要将石子有次序地合并成一堆.规定每次只能选相邻的2堆合并成新的一堆,并将新的一堆的石子数,记为该次合并的得分。
试设计出1个算法,计算出将N堆石子合并成1堆的最小得分和最大得分.
输入输出格式
输入格式:
数据的第1行试正整数N,1≤N≤100,表示有N堆石子.第2行有N个数,分别表示每堆石子的个数.
输出格式:
输出共2行,第1行为最小得分,第2行为最大得分.
输入输出样例
输入样例#1: 复制
4
4 5 9 4
输出样例#1: 复制
43
54
题解:咳咳,环形区间dp(没找到线性的唉…)用和数组(前缀和)先统计,然后先枚举长度,在枚举左端点i,可计算出j。再枚举断点k即可!
#include<bits/stdc++.h> #include<iostream> #include<algorithm> #include<queue> #include<cmath> #include<cstring> #include<cstdlib> #include<cstdio> using namespace std; const int oo=2099999999; int n,a[205],f1[205][205],f2[205][205],sum[205]; int main(){ freopen("1880.in","r",stdin); freopen("1880.out","w",stdout); scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); a[i+n]=a[i]; } for(int i=1;i<=2*n;i++) sum[i]=sum[i-1]+a[i]; //memset(f2,0x3f3f3f3f,sizeof(f2)); //for(int i=1;i<=n;i++) f2[i][i]=0; for(int l=2;l<=n;l++){ for(int i=1;i<=2*n-l+1;i++){ int j=i+l-1; f1[i][j]=0; f2[i][j]=oo; for(int k=i;k<j;k++){ f1[i][j]=max(f1[i][j],f1[i][k]+f1[k+1][j]); f2[i][j]=min(f2[i][j],f2[i][k]+f2[k+1][j]); } f1[i][j]+=(sum[j]-sum[i-1]); f2[i][j]+=(sum[j]-sum[i-1]); } } int ans1=0,ans2=oo; for(int i=1;i<=n;i++){ ans1=max(ans1,f1[i][i+n-1]); ans2=min(ans2,f2[i][i+n-1]); } printf("%d\n%d",ans2,ans1); return 0; }