题目
有n堆石子排成一列,每堆石子有一个重量w[i], 每次合并可以合并相邻的两堆石子,一次合并的代价为两堆石子的重量和w[i]+w[i+1]。问安排怎样的合并顺序,能够使得总合并代价达到最小。
分析
为什么这次不写codevs 1048呢?
根本无能为力,
所以要介绍一种新的方法
非动态规划GarsiaWachs
动态规划也可以做,但是我不会(用到四边形不等式)
设一个序列是A[0..n-1],每次寻找最小的一个满足A[k-1]<=A[k+1]的k,那么我们就把A[k]与A[k-1]合并,之后从k向前寻找第一个满足A[j]>A[k]+A[k-1]的j,把合并后的值A[k]+A[k-1]插入A[j]的后面。
神奇地过了,
(用平衡树优化
,可是我不会)
代码
#include <cstdio>
using namespace std;
int a[50001],t,ans,n;
int in(){
int ans=0; char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans;
}
void comb(int k){
int tmp=a[k]+a[k-1],d; ans+=tmp; t--;
for (int i=k;i<t;i++) a[i]=a[i+1];
int j=0;
for (j=k-1;j&&a[j-1]<tmp;j--) a[j]=a[j-1];
a[j]=tmp;
while (j>=2&&a[j]>=a[j-2]) d=t-j,comb(j-1),j=t-d;
}
int main(){
while (1){
n=in();
if (!n) return 0;
for (int i=0;i<n;i++) a[i]=in();
t=1; ans=0;
for (int i=1;i<n;i++){
a[t++]=a[i];
while (t>=3&&a[t-3]<=a[t-1]) comb(t-2);
}
while (t>1) comb(t-1);
printf("%d\n",ans);
}
}