BZOJ-3229 石子合并 GarsiaWachs算法
2016-03-02 23:47
288 查看
经典DP?稳T
3229: [Sdoi2008]石子合并
Time Limit: 3 Sec Memory Limit: 128 MB
Submit: 426 Solved: 202
[Submit][Status][Discuss]
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
石子合并问题的专门算法GarsiaWachs算法:
先从序列中找第一个st【k】使得st【k-1】<=st【k+1】然后合并st【k-1】与st【k】;
再从序列中从k往前找第一个st【j】使得st【j】>st【k-1】+st【k】然后将这个合并后的放在j位置后;
如此往复直到只剩一堆;
此题暴力枚举即可,时间复杂度O(n^2)可以用平衡树去维护那个序列,实现O(nlogn)
对于证明,即是应用树结构的某最优balabala...
code:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> 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; } int st[50000]; int n,t; int ans=0; void work(int k) { int tmp=st[k]+st[k-1]; ans+=tmp; for (int i=k; i<t-1; i++) st[i]=st[i+1]; t--; int j=0; for (j=k-1; j>0 && st[j-1]<tmp; j--) st[j]=st[j-1]; st[j]=tmp; while (j>=2 && st[j]>=st[j-2]) { int d=t-j; work(j-1); j=t-d; } } int main() { n=read(); for (int i=0; i<n; i++) st[i]=read(); t=1;ans=0; for (int i=1; i<n; i++) { st[t++]=st[i]; while (t>=3 && st[t-3]<=st[t-1]) work(t-2); } while (t>1) work(t-1); printf("%d\n",ans); return 0; }
相关文章推荐
- 【转载】maven入门1
- Android开发实践:在任意目录执行NDK编译
- BZOJ-3229 石子合并 GarsiaWachs算法
- 利用Redis 实现多tomcat 同一用户同一环境单一在线
- 控件的移动方法
- Linux系统运维——vi的使用技巧——3
- levelDB缓存实现
- POJ 1003
- ubuntu安装图像处理库PIL
- clientdataset<---->json
- 作业一:建立博客、自我介绍、速读教材、学习进度总结
- Stack Overflow 2016最新架构探秘
- 1*2*3*……*100 求结果末尾有多少个零 网上的答案到底对不对
- sql union
- ios frame和bounds
- 数据库基础知识点
- 迅雷会员获取工具
- jstl param url redirect import
- [jQuery学习系列五 ]5-Jquery学习五-表单验证
- 设计模式之访问者模式+组合模式