[BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)

题面

给出一个长度为n的序列,选k段长度在L到R之间的区间,一个区间的值等于区间内所有元素之的和,使得k个区间的值之和最大。区间可以相交或包含,但一个区间只能被选1次.

\(n,k,L,R \leq 5 \times 10^5\)

分析

先把区间和转化成前缀和.枚举左端点\(i\),右端点的范围为\([i+L-1,\min(i+R-1,n)]\).在这个区间里面找一个前缀和最大的位置p,答案就是\(sum[p]-sum[i-1]\).静态维护区间最大值位置可以用ST表做。

但是我们要求k个最大区间,只把每个左端点对应的最大答案求出来,可能不够k个。对于每个左端点暴力枚举所有区间,把所有的值加入堆,最后取出k个显然也会超时。

我们维护一个堆(实现上用STL优先队列),堆里面的每个元素都是一个三元组\((i,l,r)\).表示区间左端点在\(i\),右端点在\([l,r]\)内时能取到的最大值.设\(f_m(l,r)\)为\([L,R]\)内的最大值位置,那么我们按照\(sum[f_m(l,r)]-sum[i]\)维护一个最大堆。初始时把\((i,i+L-1,min(i+R-1,n))\)插入堆。每次取堆顶\((i,l,r),\)累加堆顶的值。令\(f_m(l,r)=p\),那次大值对应的区间右端点应该在\([l,p-1]\)或\([p+1,r]\)内。于是弹出堆顶,插入\((i,l,p-1),(i,p+1,r)\)。这样做k次,就可以求出答案。

ST表查询是\(O(1)\)的,故总时间复杂度为\(O((n+k)\log n)\)

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define maxn 500000
#define maxlogn 25
using namespace std;
typedef long long ll;
int n,k,L,R;
struct sparse_table{
int log2[maxn+5];
int st[maxn+5][maxlogn+5];
void ini(ll *a,int n){
log2[0]=-1;
for(int i=1;i<=n;i++) log2[i]=log2[i>>1]+1;
for(int i=1;i<=n;i++) st[i][0]=i;
for(int j=1;j<=log2[n]+1;j++){
for(int i=1;i+(1<<(j-1))<=n;i++){
if(a[st[i][j-1]]>a[st[i+(1<<(j-1))][j-1]]) st[i][j]=st[i][j-1];
else st[i][j]=st[i+(1<<(j-1))][j-1];
}
}
}
int query(ll *a,int l,int r){
int k=log2[r-l+1];
if(a[st[l][k]]>a[st[r-(1<<k)+1][k]]) return st[l][k];
else return st[r-(1<<k)+1][k];
}
}T; int a[maxn+5];
ll sum[maxn+5];
struct node{
int l;
int r;
int i;
inline ll val(){
return sum[T.query(sum,l,r)]-sum[i-1];
}
node(){ }
node(int _i,int _l,int _r){
i=_i;
l=_l;
r=_r;
}
friend bool operator < (node p,node q){
return p.val()<q.val();
}
};
priority_queue<node>q;
int main(){
scanf("%d %d %d %d",&n,&k,&L,&R);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
sum[i]=sum[i-1]+a[i];
}
T.ini(sum,n);
for(int i=1;i+L-1<=n;i++){
q.push(node(i,i+L-1,min(i+R-1,n)));
}
ll ans=0;
for(int i=1;i<=k;i++){
node now=q.top();
q.pop();
ans+=now.val();
int p=T.query(sum,now.l,now.r);
if(p>now.l) q.push(node(now.i,now.l,p-1));
if(p<now.r) q.push(node(now.i,p+1,now.r));
}
printf("%lld\n",ans);
}

[BZOJ 2006] [NOI 2010]超级钢琴(贪心+ST表+堆)的更多相关文章

  1. ●BZOJ 2006 NOI 2010 超级钢琴

    题链: http://www.lydsy.com/JudgeOnline/problem.php?id=2006 题解: RMQ + 优先队列 (+ 前缀) 记得在一两个月前,一次考试考了这个题目的简 ...

  2. bzoj 2006: [NOI2010]超级钢琴【st表+堆】

    设计一个五元组(i,l,r,p,v),表示在以i为左端点,右端点落在(l,r)中的情况下,取最大值v时右端点落在p.把这个五元组塞到优先队列里,以v排序,每次取出一个,然后把这个取过的五元组分成两个( ...

  3. BZOJ2006:超级钢琴(ST表+堆求前K大区间和)

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

  4. [NOI 2010]超级钢琴

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

  5. 【题解】 bzoj2006: [NOI2010]超级钢琴 (ST表+贪心)

    题面戳我 Solution 不会,看的题解 Attention 哇痛苦,一直不会打\(ST\)表,我是真的菜啊qwq 预处理 Log[1]=0;two[0]=1; for(int i=2;i<= ...

  6. 解题:NOI 2010 超级钢琴

    题面 WC时候写的题,补一下 做法比较巧妙:记录每个位置和它当前对应区间的左右端点,做前缀和之后重载一下小于号,用优先队列+ST表维护当前最大值.这样贡献就是区间最大值和端点左边差分一下,可以O(1) ...

  7. 【BZOJ 2006】[NOI2010]超级钢琴 ST

    我们先把所有最左端对应的最优右端入堆,eg: z  在[l,r](由题目给出的L,R决定)之间的最优解 y,然后出堆以后,再入堆z,y-1,z,y+1,那么我们只需要用st找最大前缀和就好了(ST是一 ...

  8. JZOJ 5409 Fantasy & NOI 2010 超级钢琴 题解

    其实早在 2020-12-26 的比赛我们就做过 5409. Fantasy 这可是紫题啊 题目大意 给你一个序列,求长度在 \([L,R]\) 区间内的 \(k\) 个连续子序列的最大和 题解 如此 ...

  9. BZOJ 2006: [NOI2010]超级钢琴 ST表+堆

    开始想到了一个二分+主席树的 $O(n\log^2 n)$ 的做法. 能过,但是太无脑了. 看了一下题解,有一个 ST 表+堆的优美解法. 你发现肯定是选取前 k 大最优. 然后第一次选的话直接选固定 ...

随机推荐

  1. @JsonView注解指定返回的model类中显示的字段

    1.User类 package com.imooc.model; import com.fasterxml.jackson.annotation.JsonView; /** * @author oy ...

  2. C/C++中结构体引用中箭头->与点.的区别

    1.作用 ->主要用于类类型的指针访问类的成员,而.运算符,主要用于类类型的对象访问类的成员. 举例: class A { public : int member; } A a; //定义一个结 ...

  3. 【转载】What is the difference between authorized_keys and known_hosts file for SSH?

    The known_hosts file lets the client authenticate the server, to check that it isn't connecting to a ...

  4. java语言课堂动手动脑

    1 运行 TestInherits.java 示例,观察输出,注意总结父类与子类之间构造方法的调用关系修改Parent构造方法的代码,显式调用GrandParent的另一个构造函数,注意这句调用代码是 ...

  5. prometheus-pushgateway安装

    背景 当prometheus的server与target不在同一网段网络不通,无法直接拉取target数据,需要使用pushgateway作为数据中转点. 弊端 将多个节点数据汇总到 pushgate ...

  6. Eating Plan

    Eating Plan 2019南昌G 模数为合数,所以只有约3000个数字不为0 记录一下不为0的数字位置 H[x]代表距离为x的连续段的数字和的最大值 处理出H[x] 再H[x] = max(H[ ...

  7. OI常用的常数优化小技巧

    注意:本文所介绍的优化并不是算法上的优化,那个就非常复杂了,不同题目有不同的优化.笔者要说的只是一些实用的常数优化小技巧,很简单,虽然效果可能不那么明显,但在对时间复杂度要求十分苛刻的时候,这些小的优 ...

  8. [HDU4336]:Card Collector(概率DP)

    题目传送门 题目描述 夏川的生日就要到了.作为夏川形式上的男朋友,季堂打算给夏川买一些生日礼物.商店里一共有种礼物.夏川每得到一种礼物,就会获得相应喜悦值$W_i$(每种礼物的喜悦值不能重复获得).每 ...

  9. 一款新的好用的SSH工具——FinalShell,比XShell更牛逼~

    FinalShell是一体化的的服务器,网络管理软件,不仅是ssh客户端,还是功能强大的开发,运维工具,充分满足开发,运维需求.特色功能:免费海外服务器远程桌面加速,ssh加速,双边tcp加速,内网穿 ...

  10. Jquery EasyUI tree 的异步加载(遍历指定文件夹,根据文件夹内的文件生成tree)

    private void SMT(HttpContext context) { string SqlConnection82 = System.Configuration.ConfigurationM ...