【题解】[P2048 NOI2010]超级钢琴

一道非常套路的题目。是堆的套路题。

考虑前缀和,我们要是确定了左端点,就只需要在右端区间查询最大的那个加进来就好了。\(sum_j-sum_{i-1}​\)嘛,我们预处理对于\(sum​\)的\(st​\)表,然后枚举\(i​\),然后记五元组\(sum,i,l,pos,r​\)分别表示这个五元组的\(sum_{pos}-sum_{i-1}​\)贡献,左端点\(i​\),右边范围\(l,r​\),和上次使用的下标\(pos​\) 。

先把所有的\((sum,i,i+L-1,maxpos,i+R-1)​\)压入大根堆,按照\(sum​\)排序

取出队头后,将五元组拆为\((sum',i,i+L-1,maxpos',maxpos-1)\)和\((sum'',i,maxpos+1,maxpos'',i+R-1)\)再放入堆里。

上面五元组的拆分只是意会,在代码中有些小细节不一样,不一定是\(i+L-1\),\(i+R-1\)

这样连续操作\(k\)次,他们的和就是我们要的答案。

#include<bits/stdc++.h>

using namespace std;typedef long long ll;
#define DRP(t,a,b) for(register int t=(a),edd=(b);t>=edd;--t)
#define RP(t,a,b) for(register int t=(a),edd=(b);t<=edd;++t)
#define ERP(t,a) for(register int t=head[a];t;t=e[t].nx)
#define midd register int mid=(l+r)>>1
#define TMP template < class ccf >
TMP inline ccf qr(ccf b){
register char c=getchar();register int q=1;register ccf x=0;
while(c<48||c>57)q=c==45?-1:q,c=getchar();
while(c>=48&&c<=57)x=x*10+c-48,c=getchar();
return q==-1?-x:x;}
TMP inline ccf Max(ccf a,ccf b){return a<b?b:a;}
TMP inline ccf Min(ccf a,ccf b){return a<b?a:b;}
TMP inline ccf Max(ccf a,ccf b,ccf c){return Max(a,Max(b,c));}
TMP inline ccf Min(ccf a,ccf b,ccf c){return Min(a,Min(b,c));}
TMP inline void READ(ccf* _arr,int _n){RP(t,1,_n)_arr[t]=qr((ccf)1)+_arr[t-1];}
TMP inline void Swap(ccf a,ccf b){ccf c;c=b;b=a;a=c;}
//----------------------template&IO---------------------------
#define int long long
const int maxn=500005;
int data[maxn];
int lg[maxn];
struct ST{
int sum,id;
inline bool operator <(ST a)const{return sum==a.sum?id<a.id:sum<a.sum;}
}st[maxn][32];
int n,lb,rb,k;
inline int qint(int l,int r){return Max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]).sum;}
inline int qpos(int l,int r){return Max(st[l][lg[r-l+1]],st[r-(1<<lg[r-l+1])+1][lg[r-l+1]]).id ;}
struct node{
int sum,i,L,pos,R;
inline bool operator < (node a)const{return sum==a.sum?pos<a.pos:sum<a.sum;}
};
priority_queue < node > q; inline node mk(int sum,int i,int L,int pos,int R){node ret=(node){sum,i,L,pos,R};return ret;}
signed main(){
#ifndef ONLINE_JUDGE
freopen("sequence1.in","r",stdin);
freopen("sequence.out","w",stdout);
#endif
n=qr(1);k=qr(1);lb=qr(1);rb=qr(1);
READ(data,n);
const int* sum=data;
RP(t,1,n+1){
lg[t]=lg[t-1];
if((1<<lg[t]<<1)==t)lg[t]++; }
int ans=0;
int L=lb,R=rb;
RP(t,1,n) st[t][0].sum=data[t],st[t][0].id=t;
DRP(t,n,1){
st[t][0].sum=data[t];st[t][0].id=t;
RP(i,1,lg[n-t+1]) st[t][i]=Max(st[t][i-1],st[t+(1<<(i-1))][i-1]);
}
RP(t,1,n){
if(t+R-1<=n) q.push(mk(qint(t+L-1,t+R-1)-sum[t-1],t,t+L-1,qpos(t+L-1,t+R-1),t+R-1));
else if(t+L-1<=n) q.push(mk(qint(t+L-1,n) -sum[t-1],t,t+L-1,qpos(t+L-1,n) ,n ));
}
RP(qaqqqq,1,k){
register node now=q.top();q.pop();
ans+=now.sum;
if(now.pos>now.L&&now.pos<=now.R) q.push(mk(qint(now.L,now.pos-1)-sum[now.i-1],now.i,now.L,qpos(now.L,now.pos-1),now.pos-1));
if(now.pos<now.R&&now.pos>=now.L) q.push(mk(qint(now.pos+1,now.R)-sum[now.i-1],now.i,now.pos+1,qpos(now.pos+1,now.R),now.R));
}
cout<<ans<<endl;
return 0;
}

【题解】P2048 [NOI2010]超级钢琴的更多相关文章

  1. P2048 [NOI2010]超级钢琴(RMQ+堆+贪心)

    P2048 [NOI2010]超级钢琴 区间和--->前缀和做差 多次查询区间和最大--->前缀和RMQ 每次取出最大的区间和--->堆 于是我们设个3元组$(o,l,r)$,表示左 ...

  2. 洛谷 P2048 [NOI2010]超级钢琴 解题报告

    P2048 [NOI2010]超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为 ...

  3. [洛谷P2048] [NOI2010] 超级钢琴

    洛谷题目链接:[NOI2010]超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号 ...

  4. LGOJ P2048 [NOI2010]超级钢琴

    题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中A ...

  5. 洛谷P2048 [NOI2010]超级钢琴 题解

    2019/11/14 更新日志: 近期发现这篇题解有点烂,更新一下,删繁就简,详细重点.代码多加了注释.就酱紫啦! 正解步骤 我们需要先算美妙度的前缀和,并初始化RMQ. 循环 \(i\) 从 \(1 ...

  6. 洛谷 P2048 [NOI2010]超级钢琴 || Fantasy

    https://www.luogu.org/problemnew/show/P2048 http://www.lydsy.com/JudgeOnline/problem.php?id=2006 首先计 ...

  7. Luogu P2048 [NOI2010]超级钢琴

    这道题题号很清新啊!第一次开NOI的题,因为最近考到了这道题的升级版. 我们先考虑\(O(n^2)\)大暴力,就是枚举前后端点然后开一个前缀和减一下即可. 然后引入正解,我们设一个三元组\(F(s,l ...

  8. P2048 [NOI2010]超级钢琴 (RMQ,堆)

    大意: 给定n元素序列a, 定义一个区间的权值为区间内所有元素和, 求前k大的长度在[L,R]范围内的区间的权值和. 固定右端点, 转为查询左端点最小的前缀和, 可以用RMQ O(1)查询. 要求的是 ...

  9. P2048 [NOI2010]超级钢琴

    传送门 考虑维护前缀和 $sum[i]$ 那么对于每一个位置 $i$ ,左端点为 $i$ 右端点在 $[i+L-1,i+R-1]$ 区间的区间最大值容易维护 维护三元组 $(o,l,r)$ ,表示左端 ...

随机推荐

  1. oracle如何获得新插入记录的id

    .对于提交(最后一次操作commit了)的话可以查询那个提交段 SELECT 列名1,列名2…… FROM 表名 VERSIONS BETWEEN TIMESTAMP MINVALUE AND MAX ...

  2. windows 屏幕坐标 窗口坐标 客户区坐标 逻辑坐标 设备坐标之间的关系及转换

    设置坐标映射    (1)Windows坐标系统 Windows坐标系分为逻辑坐标系和设备坐标系两种,GDI支持这两种坐标系.一般而言, GDI的文本和图形输出函数使用逻辑坐标,而在客户区移动或按下鼠 ...

  3. 2016.7.12 eclispe使用mybatis generator生成代码时提示project E is not exist

    运行mybatis-generator之后,出现错误:project E is not exist   错误原因:使用了项目的绝对路径. http://bbs.csdn.net/topics/3914 ...

  4. &lt;LeetCode OJ&gt; 83. Remove Duplicates from Sorted List

    83. Remove Duplicates from Sorted List Total Accepted: 94387 Total Submissions: 264227 Difficulty: E ...

  5. H5 性能调优 工具

    1.阿里测:http://www.alibench.com 2.奇云测:http://ce.cloud.360.cn 3.百度应用性能检测中心:http://apm.baidu.com 推荐理由:这3 ...

  6. linux驱动开发重点关注内容--摘自《嵌入式Linux驱动模板精讲与项目实践》

    本文摘自本人拙著 <嵌入式Linux驱动模板精讲与项目实践> 初步看起来Linux设备驱动开发涉及内容非常多,而须要实现驱动的设备千差万别.事实上做一段时间驱动之后回首看来主要就是下面几点 ...

  7. hint指定index的深入理解

    http://czmmiao.iteye.com/blog/1480247创建一个表,含有位图index和b-tree index SQL> create table t as select o ...

  8. 可以添加自定义的Select控件

    1.控件dom <select name="WebSiteTarget" id="WebSiteTarget" class="w1" ...

  9. setTimeout()基础/setInterval()基础

    JavaScript提供定时执行代码的功能,叫做定时器(timer),主要由setTimeout()和setInterval()这两个函数来完成.它们向任务队列添加定时任务.初始接触它的人都觉得好简单 ...

  10. Git小玩

    早就听说了GitHub的强大. 一直没有机会去看, 在公司实习的几个月里也没机会接触SVN和Git,  可是抱着对Linus大神的崇敬, 和开源的崇敬之情.  趁着不忙的几天, 来学习一下Git. 希 ...