这道题题号很清新啊!第一次开NOI的题,因为最近考到了这道题的升级版

我们先考虑\(O(n^2)\)大暴力,就是枚举前后端点然后开一个前缀和减一下即可。

然后引入正解,我们设一个三元组\(F(s,l,r)\)表示以\(s\)为左端点,右端点的范围在\([l,r]\)的时候最优的右端点为多少。

左端点确定了,右端点的区间也确定了,那么右端点的位置怎么求?

RMQ直接查询即可。由于要求值最大,因此我们RMQ出前缀和最大值即可

然后我们就可以得到一些三元组,考虑如何计算答案。

我们还是通过取最大值这点性质想到。因此我们用大根堆来维护,而要维护的东西应该就是这个区间的值了。

然后前缀和的作用就出来了。我们在比较时让键值为\(sum_t-sum_{s-1}\)即可。

当我们取出一个解时,注意以\(s\)为左端点的区间就不是没有用了,我们可以把它按选择的最优位置分裂成两半然后再扔回堆里为后续的做准备。

具体实现看CODE

#include<cstdio>
#include<cctype>
#include<queue>
using namespace std;
const int N=500005,P=25;
int n,k,l,r,sum[N],log[N];
long long ans;
struct data
{
int s,l,r,t;
bool operator <(const data x) const { return sum[x.t]-sum[x.s-1]>sum[t]-sum[s-1]; }
};
struct RMQ
{
int x,num;
}f[N][P];
priority_queue<data> big;
inline char tc(void)
{
static char fl[100000],*A=fl,*B=fl;
return A==B&&(B=(A=fl)+fread(fl,1,100000,stdin),A==B)?EOF:*A++;
}
inline void read(int &x)
{
x=0; char ch; int flag=1; while (!isdigit(ch=tc())) flag=ch^'-'?1:-1;
while (x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc())); x*=flag;
}
inline int min(int a,int b)
{
return a<b?a:b;
}
inline void log_init(void)
{
for (register int i=2;i<=n;++i)
log[i]=log[i>>1]+1;
}
inline void RMQ_init(void)
{
for (register int j=1;j<P;++j)
for (register int i=1;i+(1<<j)-1<=n;++i)
f[i][j]=f[i][j-1].x>f[i+(1<<j-1)][j-1].x?f[i][j-1]:f[i+(1<<j-1)][j-1];
}
inline int query(int l,int r)
{
int k=log[r-l+1];
return f[l][k].x>f[r-(1<<k)+1][k].x?f[l][k].num:f[r-(1<<k)+1][k].num;
}
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
register int i; read(n); read(k); read(l); read(r);
for (i=1;i<=n;++i)
read(sum[i]),sum[i]+=sum[i-1],f[i][0]=((RMQ){sum[i],i});
log_init(); RMQ_init();
for (i=1;i<=n;++i)
if (i+l-1<=n) big.push((data){i,i+l-1,min(n,i+r-1),query(i+l-1,min(n,i+r-1))});
while (k--)
{
data now=big.top(); big.pop(); ans+=sum[now.t]-sum[now.s-1];
if (now.l^now.t) big.push((data){now.s,now.l,now.t-1,query(now.l,now.t-1)});
if (now.r^now.t) big.push((data){now.s,now.t+1,now.r,query(now.t+1,now.r)});
}
return printf("%lld",ans),0;
}

Luogu 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]超级钢琴

    [题解][P2048 NOI2010]超级钢琴 一道非常套路的题目.是堆的套路题. 考虑前缀和,我们要是确定了左端点,就只需要在右端区间查询最大的那个加进来就好了.\(sum_j-sum_{i-1}​ ...

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

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

  5. LGOJ P2048 [NOI2010]超级钢琴

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

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

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

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

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

  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. retrofit框架接口调用时候报Throwing new exception

    最近在开发的时候遇到了一个很坑的问题,在三星6.0手机上请求接口时候报了一个异常:Throwing new exception 'length=1658; index=3248' with unexp ...

  2. C#项目实践之一——WPF多媒体通讯录

    1.Window.Resources  是一种Window级的资源定义. Window.Resources它的作用范围就是在Window容器里的所有子控件,也只有这些子控件才能引用/调用这些资源 Gr ...

  3. [java大数据面试] 2018年4月百度面试经过+三面算法题:给定一个数组,求和为定值的所有组合.

    给定一个数组,求和为定值的所有组合, 这道算法题在leetcode应该算是中等偏下难度, 对三到五年工作经验主要做业务开发的同学来说, 一般较难的也就是这种程度了. 简述经过: 不算hr面,总计四面, ...

  4. cglib之Enhancer

    1. 背景 cglib库的Enhancer在Spring AOP中作为一种生成代理的方式被广泛使用.本文针对Enhancer的用法以实际代码为例作一些介绍. 2. Enhancer是啥 Enhance ...

  5. golang xorm框架的使用

    1.创建engine engine, err := xorm.NewEngine(driverName, dataSourceName) 上述代码创建了一个数据库引擎,可以在一个程序中创建多个engi ...

  6. IO流_文件切割与合并(带配置信息)

    在切割文件的时候应该生成一个记录文件信息的文件,以便在以后合并文件的时候知道这个文件原来的文件名和记录文件切割完后生成了多少个切割文件 import java.io.File; import java ...

  7. python 之 初识面向对象

    编程的两种范式 我们知道,程序 = 特定的语法+数据结构+算法 好像这个和我们熟知的小说有类似之处啊,小说 = 人物+背景+情节 写小说呢,都是有模板的,so,写程序也是一样,我们把这个“模板”叫做编 ...

  8. sys.argv[]使用

    sys.argv[]说白了就是一个从程序外部获取参数的桥梁,这个"外部"很关键,所以那些试图从代码来说明它作用的解释一直没看明白.因为我们从外部取得的参数可以是多个,所以获得的是一 ...

  9. innerHTML、innerText和outerHTML、outerText的区别

    区别描述如下: innerHTML 设置或获取位于对象起始和结束标签内的 HTML outerHTML 设置或获取对象及其内容的 HTML 形式 innerText 设置或获取位于对象起始和结束标签内 ...

  10. 转:// 再说 Oracle RAC services

    应用程序工作负载在Oracle 10g中可以被定为services,也称之为服务,能够在单实例中使用,也能够在RAC中单独使用和管理.因此整个数据库负载能够被分割为多个不同的services,通过管理 ...