题目描述

小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的
音乐。 这架超级钢琴可以弹奏出n个音符,编号为1至n。第i个音符的美妙度为Ai,其中Ai可正可负。 一个“超级
和弦”由若干个编号连续的音符组成,包含的音符个数不少于L且不多于R。我们定义超级和弦的美妙度为其包含的
所有音符的美妙度之和。两个超级和弦被认为是相同的,当且仅当这两个超级和弦所包含的音符集合是相同的。 
小Z决定创作一首由k个超级和弦组成的乐曲,为了使得乐曲更加动听,小Z要求该乐曲由k个不同的超级和弦组成。
我们定义一首乐曲的美妙度为其所包含的所有超级和弦的美妙度之和。小Z想知道他能够创作出来的乐曲美妙度最
大值是多少。

输入

第一行包含四个正整数n, k, L, R。其中n为音符的个数,k为乐曲所包含的超级和弦个数,L和R分别是超级和弦所
包含音符个数的下限和上限。 接下来n行,每行包含一个整数Ai,表示按编号从小到大每个音符的美妙度。
N<=500,000
k<=500,000
-1000<=Ai<=1000,1<=L<=R<=N且保证一定存在满足条件的乐曲

输出

只有一个整数,表示乐曲美妙度的最大值。

样例输入

4 3 2 3
3
2
-6
8

样例输出

11
【样例说明】
共有5种不同的超级和弦:
音符1 ~ 2,美妙度为3 + 2 = 5
音符2 ~ 3,美妙度为2 + (-6) = -4
音符3 ~ 4,美妙度为(-6) + 8 = 2
音符1 ~ 3,美妙度为3 + 2 + (-6) = -1
音符2 ~ 4,美妙度为2 + (-6) + 8 = 4
最优方案为:乐曲由和弦1,和弦3,和弦5组成,美妙度为5 + 2 + 4 = 11。
 
区间和可以转化成两个前缀和相减。
先考虑怎么找最大的区间和。
因为对于每个左端点i,能选的右端点是一段区间即[i+L-1,i+R-1]。
那么只要枚举以每个点为左端点,找到能选的右端点区间中的最大前缀和,取这些右端点和左端点(实际上是左端点前面那个点)差值的最大值就是最大的区间和。
那么选完最大值,再考虑第二大的。只要在剩下的那些以每个点为左端点的区间最大值中选最大的就好了?
显然不一定,假设刚才选的那个区间左端点为i,那么以i为左端点的能选的区间中第二大的可能比其他的那些最大值还大。
而这个第二大的相当于是删除了刚才第一大的后,以i为左端点的能选区间中第一大的。
因此我们只要每次在以每个点为左端点的右端点能选区间中找到最大值,在所有最大值中取出最大的,然后再把这个最大的删掉,下次再取剩下最大的就好了。
具体点来说就是用堆维护当前所有取出区间的最大值(堆中每个元素存区间和以及这个区间和的左端点两个信息),记录以每个点为左端点时右端点能选区间中已经取了前几大的,每次弹出堆顶元素,假设堆顶元素区间的左端点是i,而以i为左端点的右端点区间中已经取了j个,就再找到第j+1大的右端点,再把i和这个点构成的区间和插入堆中。
至于区间第k大,直接用主席树维护就好了。
注意如果能取的右端点区间长度小于当前要取的k大小时就不能取了。
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<vector>
#include<bitset>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
#define pr pair<int,int>
using namespace std;
ll ans;
int n,m;
int x,y;
int L,R;
int cnt;
int s[500010];
int t[500010];
int root[500010];
int ls[30000010];
int rs[30000010];
int sum[30000010];
priority_queue<pr>q;
void updata(int &rt,int pre,int l,int r,int k)
{
rt=++cnt;
sum[rt]=sum[pre]+1;
ls[rt]=ls[pre];
rs[rt]=rs[pre];
if(l==r)
{
return ;
}
int mid=(l+r)>>1;
if(k<=mid)
{
updata(ls[rt],ls[pre],l,mid,k);
}
else
{
updata(rs[rt],rs[pre],mid+1,r,k);
}
}
int query(int x,int y,int l,int r,int k)
{
if(l==r)
{
return l;
}
int res=sum[rs[y]]-sum[rs[x]];
int mid=(l+r)>>1;
if(res<k)
{
return query(ls[x],ls[y],l,mid,k-res);
}
else
{
return query(rs[x],rs[y],mid+1,r,k);
}
}
int main()
{
scanf("%d%d%d%d",&n,&m,&L,&R);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
s[i]=s[i-1]+x;
updata(root[i],root[i-1],0,1000000000,s[i]+500000000);
}
for(int i=1;i+L-1<=n;i++)
{
t[i]++;
x=query(root[i+L-2],root[min(n,i+R-1)],0,1000000000,t[i]);
q.push(make_pair(x-s[i-1],i));
}
while(m)
{
pr miku=q.top();
q.pop();
m--;
x=miku.first;
y=miku.second;
ans+=1ll*(x-500000000);
if(t[y]<min(n,y+R-1)-(y+L-1)+1)
{
t[y]++;
x=query(root[y+L-2],root[min(n,y+R-1)],0,1000000000,t[y]);
q.push(make_pair(x-s[y-1],y));
}
}
printf("%lld",ans);
}

BZOJ2006[NOI2010]超级钢琴——堆+主席树的更多相关文章

  1. BZOJ 2006 [NOI2010]超级钢琴 (堆+主席树)

    题面:BZOJ传送门 洛谷传送门 让你求前$K$大的子序列和,$n\leq 5*10^{5}$ 只想到了个$nlog^{2}n$的做法,似乎要被卡常就看题解了.. 好神奇的操作啊,我傻了 我们把序列和 ...

  2. 【BZOJ2006】超级钢琴(主席树,优先队列)

    [BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...

  3. BZOJ 2006 超级钢琴(堆+主席树)

    很好的一道题. 题意:给出长度为n的数列,选择k个互不相同的区间,满足每个区间长度在[L,R]内,求所有选择的区间和的总和最大是多少.(n,k<=5e5). 首先将区间和转化为前缀和之差,那么我 ...

  4. luogu2048 [NOI2010]超级钢琴 (优先队列+主席树)

    思路:先扫一遍所有点作为右端点的情况,把它们能产生的最大值加到一个优先队列里,然后每次从优先队列里取出最大值,再把它对应的区间的次大值加到优先队列里,这样做K次 可以用一个前缀和,每次找i为右端点的第 ...

  5. 【BZOJ2006】【NOI2010】超级钢琴(主席树,优先队列)

    [BZOJ2006]超级钢琴(主席树,优先队列) 题面 BZOJ 题解 既然是一段区间 首先就要变成单点 所以求一个前缀和 这个时候贪心很明显了: 枚举每一个点和可以和它组成一段的可行的点 全部丢进一 ...

  6. bzoj2006 [NOI2010]超级钢琴 (及其拓展)

    bzoj2006 [NOI2010]超级钢琴 给定一个序列,求长度在 \([L,\ R]\) 之间的区间和的前 \(k\) 大之和 \(n\leq5\times10^5,\ k\leq2\times1 ...

  7. [BZOJ2006] [NOI2010]超级钢琴 主席树+贪心+优先队列

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MBSubmit: 3591  Solved: 1780[Submit][Statu ...

  8. BZOJ2006 [NOI2010]超级钢琴 【堆 + RMQ】

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 552 MB Submit: 3446  Solved: 1692 [Submit][Sta ...

  9. [BZOJ2006][NOI2010]超级钢琴(ST表+堆)

    2006: [NOI2010]超级钢琴 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3679  Solved: 1828[Submit][Statu ...

随机推荐

  1. Android学习之基础知识四-Activity活动4讲(Intent传递数据)

    Intent除了可以开启一个活动,还能在启动活动的时候传递数据,此时Intent相当于一个保存数据的库,我们先把数据保存在Intent中,然后再根据各个activity的需要从其中取出数据.  一.使 ...

  2. android之WIFI小车编程详述

    有了前几篇wifi模块eps8266的使用,单片机设置eps8266程序,android TCP客户端,现在就做一个wifi小车 先上图 小车是四个轮子的,每个轮子上都有电机驱动,前进后退的时候四个轮 ...

  3. C#以管理员用户打开某个程序

    static void Main(string[] args) { string path = @"C:\Windows\AppPatch\AppLoc.exe"; Process ...

  4. 3.3《想成为黑客,不知道这些命令行可不行》(Learn Enough Command Line to Be Dangerous)——less即more

    Unix提供了两个工具查看不止文件的头部和尾部.这个功能程序叫做more,但有种更强大的变异体叫做less(起初我认为这是玩笑).less这个程序是交互性地,所以很难在输出时捕获,但是仍然为大家提供了 ...

  5. WPF中反转3D列表项

    原文:WPF中反转3D列表项 WPF中反转3D列表项                                                         周银辉记得在苹果电脑中有一个很酷的 ...

  6. bat基础知识

    1.打日志:使用重定向 eg:call test.bat>log/test.log 2.不关闭cmd窗口:使用pause eg: 结果: ps:注意,在自动化运维的时候,比如创建自动发版的脚本的 ...

  7. Item 9: 比起typedef更偏爱别名声明(alias declaration)

    本文翻译自modern effective C++,由于水平有限,故无法保证翻译完全正确,欢迎指出错误.谢谢! 博客已经迁移到这里啦 我确信我们都同意使用STL容器是一个好主意,并且我希望在Item ...

  8. Jmeter(三十四)_Beanshell解析并提取json响应

    1:前置条件 将fastjson-1.2.49.jar包置于jmeter的lib目录下,并将该jar包添加到测试计划的Library中:否则会报:Typed variable declaration ...

  9. Azure Load Balancer : 简介

    Azure 提供的负载均衡服务叫 Load Balancer,它工作在 ISO 七层模型的第四层,通过分析 IP 层及传输层(TCP/UDP)的流量实现基于 "IP + 端口" 的 ...

  10. Note: SE Class's Individual Project

    虽然第一个Project还有点小问题需要修改,但是大体已经差不多了,先把blog记在这里,算是开博第一篇吧! 1.项目预计的用时 本来看到这个题的时候想的并不多,但是看了老师的要求才觉得如此麻烦ORZ ...