BZOJ 3229[Sdoi2008]石子合并 GarsiaWachs算法

xiaoxiao2021-02-28  111

Description

  在一个操场上摆放着一排 N 堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的 2 堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。   试设计一个算法,计算出将 N 堆石子合并成一堆的最小得分。  

Input

  第一行是一个数 N   以下 N 行每行一个数 A ,表示石子数目。  

Output

  共一个数,即N堆石子合并成一堆的最小得分。

 

Sample Input

4 1 1 1 1

Sample Output

8

HINT

对于 100% 的数据,1≤N≤40000 对于 100% 的数据,1≤A≤200

Source

传送门 原版的石子合并,N却有整整40000…… 基本的DP是O(N^3)的, 平行四边形优化过后是O(N^2)的,但是仍然不能满足这题的条件。 这里要用到GarsiaWachs算法。 步骤: 1.找到第一个a[u-1]<=a[u+1]的位置; 2.将a[u-1]和a[u]合并(加起来); 3.把合并后的结果插入到位置v,使得a[v]>=a[u]。 如此重复上述步骤,合并n-1次,得到的就是最优结果…… 其实我不太知道原理…… 证明还是网上百度吧。。。 时间复杂度O(N^2)……这是最坏情况下的,,听说平均是O(N log N) 反正加上平衡树就是稳定O(N log N)了,,(我没加) #include<bits/stdc++.h> using namespace std; int read(){ int x=0,f=1;char ch=getchar(); while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();} while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } const int N=40005, MAX=9000000; int n,a[N]; int main(){ n=read(); for (int i=1;i<=n;i++) a[i]=read(); a[0]=a[n+1]=MAX; int m=n,ans=0; for (int i=1;i<n;i++){ int k; for (int j=1;j<=m;j++) if (a[j-1]<=a[j+1]){ k=j; break; } a[k-1]+=a[k]; for (int j=k;j<m;j++) a[j]=a[j+1]; ans+=a[--k]; while (k && a[k-1]<=a[k]) swap(a[k-1],a[k]),k--; a[m--]=MAX; } printf("%d\n",ans); return 0; }
转载请注明原文地址: https://www.6miu.com/read-20649.html

最新回复(0)