Description
在一个操场上摆放着一排N堆石子。现要将石子有次序地合并成一堆。规定每次只能选相邻的2堆石子合并成新的一堆,并将新的一堆石子数记为该次合并的得分。
试设计一个算法,计算出将N堆石子合并成一堆的最小得分。
Input
第一行是一个数N。
以下N行每行一个数A,表示石子数目。
Output
共一个数,即N堆石子合并成一堆的最小得分。
Sample Input
4
1
1
1
1
1
1
1
1
Sample Output
8
HINT
对于 100% 的数据,1≤N≤40000
对于 100% 的数据,1≤A≤200
正解:GarsiaWachs算法
解题报告:
神奇的算法,居然可以把石子合并做到O(NlogN),不可思议,感到害怕。
上午讲题的时候提到了用四边形不等式得出的可以有单调性的N^2的优化DP,然而面对40000的数据还是有一点虚。
移步学习GarsiaWachs算法:http://www.cnblogs.com/lwq12138/p/5425465.html 或者 http://blog.csdn.net/Regina8023/article/details/45244733
不详细讲了。
1 //It is made by jump~ 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 #include <algorithm> 8 #include <ctime> 9 #include <vector> 10 #include <queue> 11 #include <map> 12 #include <set> 13 #ifdef WIN32 14 #define OT "%I64d" 15 #else 16 #define OT "%lld" 17 #endif 18 using namespace std; 19 typedef long long LL; 20 const int inf = 5201314; 21 const int MAXN = 40011; 22 int a[MAXN]; 23 int n; 24 LL ans; 25 26 inline int getint() 27 { 28 int w=0,q=0; 29 char c=getchar(); 30 while((c<'0' || c>'9') && c!='-') c=getchar(); 31 if (c=='-') q=1, c=getchar(); 32 while (c>='0' && c<='9') w=w*10+c-'0', c=getchar(); 33 return q ? -w : w; 34 } 35 36 inline void work(){ 37 n=getint(); 38 for(int i=1;i<=n;i++) a[i]=getint(); 39 int m=n; 40 a[0]=a[n+1]=inf; 41 for(int i=1;i<n;i++) {//最后一次不用做 42 int k; 43 for(int j=1;j<=m;j++) {//从左往右,每次找到第一个满足a[k−1]≤a[k+1]的k,然后合并a[k−1],a[k] 44 if(a[j-1]<a[j+1]) { k=j; break; } 45 } 46 a[k-1]+=a[k]; 47 for(int j=k;j<m;j++) a[j]=a[j+1];//左移 48 ans+=a[k-1]; k--;//指向当前处理结点 49 while(k>0 && a[k-1]<=a[k]) { //从当前位置开始向左找第一个a[j]>a[k−1]+a[k]的j,把合并后的值插到j的后面 50 swap(a[k-1],a[k]); 51 k--; 52 } 53 a[m]=inf; 54 m--; 55 } 56 printf(OT,ans); 57 } 58 59 int main() 60 { 61 work(); 62 return 0; 63 }