【Vijos1459】车展
2015-08-07 09:46
417 查看
【Description】
遥控车是在是太漂亮了,韵韵的好朋友都想来参观,所以游乐园决定举办m次车展。车库里共有n辆车,从左到右依次编号为1,2,…,n,每辆车都有一个展台。刚开始每个展台都有一个唯一的高度h[i]。主管已经列好一张单子:L1 R1
L2 R2
…
Lm Rm
单子上的(Li,Ri)表示第i次车展将要展出编号从Li到Ri的车。
为了更加美观,展览时需要调整展台的高度,使参展所有展台的高度相等。展台的高度增加或减少1都需花费1秒时间。由于管理员只有一个人,所以只好对每个展台依次操作。每次展览结束后,展台高度自动恢复到初始高度。
请告诉管理员为了举办所有展览,他最少需要花多少时间将展台调整好。
【Input】
第一行为两个正整数n、m。第二行共n个非负整数,表示第i辆车展台的高度h[i]。
接下来m行每行2个整数Li、Ri(Li≤Ri)。
【Output】
一个正整数,调整展台总用时的最小值。【Sample Input】
6 4 4 1 2 13 0 9 1 5 2 6 3 4 2 2
【Sample Output】
48
【题解】
看到题目的时候以为求平均数结果看到样例就不对。很简单的道理,给你一个数据:1 1000 1000 1000
将四个数都换成750(平均数750.25)明显没有将1换成1000的时间短。然后我们就要考虑这个数是哪一个。参考这里Vijos1459 车展,我们可以知道就是要求中位数。接下来就是实现的问题了,上方博文中给出了一种巧妙的O(n2)的算法。而我最近练习Treap正好就用这个写一种时间复杂度为O(n2log2n)的算法,根据数据范围:
对于50%的数据 n≤500,m≤1000;
对于80%的数据 n≤1000,m≤100000;
对于100%的数据n≤1000,m≤200000;
答案在2^64以内。
可以知道在规定时间内可以运行完。
参考代码如下:
type treap = record rnd,size,w,val:longint; //rnd记录优先,size记录子树大小,w记录和本节点数值相同的点的个数,val记录节点的值 l,r:longint; //l和r分别是左儿子和右儿子编号 sum:int64; //以此节点为根的子树中所有值的总和 end; var n,m,root,cnt:longint; tot,anstot,tmp,num:int64; h:array[0..1010] of longint; ans:array[0..1010,0..1010] of longint; tree:array[0..1010] of treap; procedure init; //读入 var i:longint; 4000 begin readln(n,m); for i:=1 to n do read(h[i]); readln; end; procedure update(k:longint); //维护节点 begin tree[k].size:=tree[tree[k].l].size+tree[tree[k].r].size+tree[k].w; tree[k].sum:=tree[tree[k].l].sum+tree[tree[k].r].sum+tree[k].val*tree[k].w; end; procedure right_rotation(var k:longint); //右旋 var tmp:longint; begin tmp:=tree[k].l; tree[k].l:=tree[tmp].r; tree[tmp].r:=k; update(k); update(tmp); k:=tmp; end; procedure left_rotation(var k:longint); //左旋 var tmp:longint; begin tmp:=tree[k].r; tree[k].r:=tree[tmp].l; tree[tmp].l:=k; update(k); update(tmp); k:=tmp; end; procedure insert(var k:longint; x:longint); //插入新节点 begin if (k=0) then begin inc(cnt); k:=cnt; tree[k].size:=1; tree[k].w:=1; tree[k].sum:=x; tree[k].val:=x; tree[k].rnd:=random(10000); tree[k].l:=0; tree[k].r:=0; exit; end; inc(tree[k].size); inc(tree[k].sum,x); if tree[k].val=x then begin inc(tree[k].w); exit; end; if x>tree[k].val then begin insert(tree[k].r,x); if tree[tree[k].r].rnd<tree[k].rnd then left_rotation(k); exit; end; if x<tree[k].val then begin insert(tree[k].l,x); if tree[tree[k].l].rnd<tree[k].rnd then right_rotation(k); end; end; function query(k,val:longint):longint; //查找中位数并记录相关值 begin if val<=tree[tree[k].l].size then exit(query(tree[k].l,val)); if (val>tree[tree[k].l].size+tree[k].w) then begin inc(tmp,tree[tree[k].l].sum+tree[k].w*tree[k].val); inc(num,tree[tree[k].l].size+tree[k].w); exit(query(tree[k].r,val-tree[tree[k].l].size-tree[k].w)); end; inc(tmp,tree[tree[k].l].sum); inc(num,tree[tree[k].l].size); exit(tree[k].val); end; procedure prep; //预先算出每个区间内的答案 var i,j,ave:longint; begin for i:=1 to n do begin //分别以1~n为根建树 cnt:=0; root:=0; tot:=0; for j:=i to n do begin inc(tot,h[j]); insert(root,h[j]); tmp:=0; num:=0; ave:=query(root,(j-i+2) div 2); inc(ans[i,j],num*ave-tmp); inc(ans[i,j],tot-tmp-(j-i+1-num)*ave); end; end; end; procedure main; var i,a,b:longint; begin for i:=1 to m do begin readln(a,b); anstot:=anstot+ans[a,b]; end; writeln(anstot); end; begin init; prep; main; end.
参考资料:
1.Vijos 车展-yywyzdzr-博客频道-CSDN.NET
2.【vijos1459】车展|treap|中位数|HZWER:WE are OIers
相关文章推荐
- 初级问题 --eclipse中代码自动更新的解决办法
- 关于Java的File.separator
- Best Time to Buy and Sell Stock II
- IntelliJIDEA中如何导入额外的jar包
- linux查找函数/查看文件夹size/tab转4空格 命令
- Eclipse添加小工具_打开当前文件所在文件夹
- Table表格做登陆页面
- 关于多线程io能否提高程序效率
- CSS中的四种选择器
- JAVA实现全角半角相互转化 (full2Half & half2Full)
- 南邮 OJ 1880 A. 偷吃可耻
- C++ Hello World
- Cypress固件架构彻底解析及USB枚举
- 延迟加载图片的 jQuery 插件:Lazy Load
- 架构师速成6.15-开发框架-单点登录
- HighCharts画时间趋势图,标示区以及点击事件操作
- 盒子模型案例一
- 【Go】Linux下使用Sublime Text搭建开发环境
- 盒子模型案例二
- 游戏开发如何成功