洛谷P2048 [NOI2010]超级钢琴 题解
2019/11/14 更新日志:
近期发现这篇题解有点烂,更新一下,删繁就简,详细重点。代码多加了注释。就酱紫啦!
正解步骤
我们需要先算美妙度的前缀和,并初始化RMQ。
循环 \(i\) 从 \(1\) 到 \(n\) ,因为以i为起点的 和弦 终点必定是 \(i + L - 1\) 到 \(i + R - 1\) 之间,所以只要在区间内用RMQ取 超级和弦 ,并加入以美妙度从小排到大的优先队列中。
取出堆顶元素,将美妙度加入 \(ans\) ,并将元素切为从 (当前元素的左边界 到 当前元素终点 - 1) 和 (\(当前元素终点 + 1 到 当前元素右边界\)) 两个部分,并再次加入优先队列,依次进行 \(k\) 次。
输出答案即可
为什么要使用前缀和 and RMQ?
数据范围是500000,很明显,为了优化需要前缀和 and RMQ。
前缀和最明显的用处,是可以优化一个用来循环累加和的 \(n\) 。而 \(RMQ\) ,显然区间最值符合题目要求。
这两个算法询问答案都是O(1)。前缀和后面减去前面,RMQ只需要初始化一下,然后O(1)询问即可。
为什么第三步要切开元素并放入优先队列? 直接累加前 \(k\) 个元素不行么?
首先,我们肯定可以确定:优先队列中第一大的和弦一定是 \(全局\) 最大的和弦。 不要问我怎么证明
那么优先队列中第二大的和弦一定是 \(全局\) 次大的和弦么?这就不一定了。
所以我们需要切开元素并放入优先队列,保证每次取出来的元素一定是全局大小排名的元素
自己拿出纸和笔,结合题解自己思考,在草稿纸上演算一下,就懂了
那我就把解题思路放上吧233
实在还有问题,私信本人233

感谢老师 @apple365 的思路指引。
AC代码
#include<bits/stdc++.h>
#include<cctype>
#pragma GCC optimize(2)
#define in(a) a = read()
#define out(a) write(a)
#define outn(a) out(a),putchar('\n')
#define ll long long
#define Min(a,b) a < b ? a : b
#define Max(a,b) a > b ? a : b
#define rg register
#define New ll
using namespace std;
namespace IO_Optimization{
inline New read()
{
New X = 0,w = 0;
char ch = 0;
while(!isdigit(ch))
{
w |= ch == '-';
ch=getchar();
}
while(isdigit(ch))
{
X = (X << 3) + (X << 1) + (ch ^ 48);
ch = getchar();
}
return w ? -X : X;
}
inline void write(New x)
{
if(x < 0) putchar('-'),x = -x;
if(x > 9) write(x/10);
putchar(x % 10 + '0');
}
#undef New
}
using namespace IO_Optimization;//上面一坨优化的东西不用在意
const int MAXN = 500000 + 2;//定义常亮
int n,k,L,R;
int sum[MAXN],lg[MAXN],dp[MAXN][20],pos[MAXN][20];
// 前缀和 lg2值
//dp[i][j]表示i的2^j次方祖先 pos数组来记录最佳位置
ll ans;
struct Node
{
int start, left, right, t, val;
//超级和弦的起点 左、右边界 最值位置 最值
bool operator < (const Node &next) const
{
return val < next.val; //最值从大到小排序
}
};
inline void RMQ_init() //预处理
{
for(rg int j = 1;j <= 20; ++j)
for(rg int i = 1;i + (1 << j) - 1 <= n; ++i)
{
if(dp[i][j - 1] > dp[i + (1 << (j - 1))][j - 1])
{
dp[i][j] = dp[i][j - 1];
pos[i][j] = pos[i][j - 1];//更新最值位置
}
else
{
dp[i][j] = dp[i + (1 << (j - 1))][j - 1];
pos[i][j] = pos[i + (1 << (j - 1))][j - 1];
}
}
return;
}
inline int RMQ_query(int l, int r) //返回最值的位置
{
int t, tmp = lg[r - l + 1];
if(dp[l][tmp] > dp[r - (1 << tmp) + 1][tmp])
t = pos[l][tmp];
else t = pos[r - (1 << tmp) + 1][tmp];
return t;
}
int main()
{
in(n),in(k),in(L),in(R);
lg[0] = -1;//lg2(0) = -1,方便后面预处理lg2值
for(rg int i = 1;i <= n; ++i)
{
int a = read();//读入音符
sum[i] = sum[i - 1] + a; //前缀和
lg[i] = lg[i >> 1] + 1; //预处理lg2值
dp[i][0] = sum[i];
pos[i][0] = i; //初始化最大值的位置
}
RMQ_init();//初始化
priority_queue<Node> pq; //定义优先队列
for(rg int i = 1;i + L - 1 <= n; ++i) //计算每个位置最大的超级和弦
{
int t = RMQ_query(i + L - 1, Min(n, i + R - 1));
Node cur;
cur.val = sum[t] - sum[i - 1]; //由前缀和取最大值
cur.t = t;
cur.start = i; //当前超级和弦的起始位置
cur.left = i + L - 1; //当前的左边界
cur.right = Min(n,i + R - 1); //当前的右边界
pq.push(cur); //入堆
}
for(rg int i = 1;i <= k; ++i) //取k次堆顶的值
{
Node cur = pq.top();
pq.pop();
ans = ans + cur.val; //累加结果
Node next;
if(cur.t > cur.left) //当前取最值的位置 大于 当前和弦的 左边界
{
next.start = cur.start;
next.left = cur.left;
next.right = cur.t - 1; //新的右边界
next.t = RMQ_query(next.left, next.right);
next.val = sum[next.t] - sum[next.start - 1];
pq.push(next);
}
if(cur.t < cur.right) //当前取最值的位置 小于 当前和弦的 右边界
{
next.start = cur.start;
next.left = cur.t + 1; //新的左边界
next.right = cur.right;
next.t = RMQ_query(next.left, next.right);
next.val = sum[next.t] - sum[next.start - 1];
pq.push(next);
}
}
outn(ans);
return 0;
}
END.
洛谷P2048 [NOI2010]超级钢琴 题解的更多相关文章
- 洛谷 P2048 [NOI2010]超级钢琴 解题报告
P2048 [NOI2010]超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为 ...
- [洛谷P2048] [NOI2010] 超级钢琴
洛谷题目链接:[NOI2010]超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号 ...
- 洛谷 P2048 [NOI2010]超级钢琴 || Fantasy
https://www.luogu.org/problemnew/show/P2048 http://www.lydsy.com/JudgeOnline/problem.php?id=2006 首先计 ...
- 洛谷 P2048 [NOI2010]超级钢琴(优先队列,RMQ)
传送门 我们定义$(p,l,r)=max\{sum[t]-sum[p-1],p+l-1\leq t\leq p+r-1 \}$ 那么因为对每一个$p$来说$sum[p-1]$是一个定值,所以我们只要在 ...
- 洛谷P0248 [NOI2010] 超级钢琴 [RMQ,贪心]
题目传送门 超级钢琴 题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符 ...
- 【题解】P2048 [NOI2010]超级钢琴
[题解][P2048 NOI2010]超级钢琴 一道非常套路的题目.是堆的套路题. 考虑前缀和,我们要是确定了左端点,就只需要在右端区间查询最大的那个加进来就好了.\(sum_j-sum_{i-1} ...
- P2048 [NOI2010]超级钢琴(RMQ+堆+贪心)
P2048 [NOI2010]超级钢琴 区间和--->前缀和做差 多次查询区间和最大--->前缀和RMQ 每次取出最大的区间和--->堆 于是我们设个3元组$(o,l,r)$,表示左 ...
- BZOJ2006:[NOI2010]超级钢琴——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=2006 https://www.luogu.org/problemnew/show/P2048#su ...
- LGOJ P2048 [NOI2010]超级钢琴
题目描述 小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐. 这架超级钢琴可以弹奏出n个音符,编号为1至n.第i个音符的美妙度为Ai,其中A ...
随机推荐
- kuma kong 团队开发的可视化&&安全的service mesh
最近service mesh 的开源产品是越来越多了,好多团队都开源了自己的解决方案 maesh 最近kong 团队也开源了自己的service meshkuma 一张参考图 说明 kuma 没有基于 ...
- javascript使用H5新版媒体接口navigator.mediaDevices.getUserMedia,做扫描二维码,并识别内容
本文代码测试要求,最新的chrome浏览器(手机APP),并且要允许chrome拍照录像权限,必须要HTTPS协议,http不支持. 原理:调用摄像头,将摄像头返回的媒体流渲染到视频标签中,再通过ca ...
- navicat提示无法连接解决办法
1.错误如下图: 2.这个是由于mysql中user表中未设置允许该ip访问导致,解决办法: 1)查下user表:select user,host from user; 这张表就是mysql.user ...
- Zabbix实战-简易教程--中间件ZooKeeper监控
一.监控思路 通过zabbix trapper方式监控,之前看到网友们都是通过定时任务进行主动上传数据,但是,zabbix还有另外一神器--自动发现,也能达到同样的功能. 二.实现步骤 1.准备脚本 ...
- CentOS 7.5 安装Oracle 11gR2 86%报错:Error in invoking target 'agent nmhs' of makefile
解决方案: 不要关闭安装过程,另外打开终端窗口,将ins_emagent.mk文件中的 (MK_EMAGENT_NMECTL)更改为$(MK_EMAGENT_NMECTL) -lnnz11,然后在安装 ...
- Attribute application@allowBackup value=(true) from AndroidManifest.xml:7:9-35
1: 在 AndroidManifest.xml 配置文件中显式配置 android:allowBackup=false. 项目中代码 allowBackup="true" 改为 ...
- Parquet介绍及简单使用(转)
==> 什么是parquet Parquet 是列式存储的一种文件类型 ==> 官网描述: Apache Parquet is a columnar storage f ...
- python-- python threadpool 的前世今生
引出 首先需要了解的是threadpool 的用途,他更适合于用到一些大量的短任务合集,而非一些时间长的任务,换句话说,适合大量的CPU密集型短任务,那些消耗时间较长的IO密集型长任务适合用协程去解决 ...
- sklearn的基本使用
https://cloud.tencent.com/developer/news/58202 简介 今天为大家介绍的是scikit-learn.sklearn是一个Python第三方提供的非常强力的机 ...
- git解决error: The following untracked working tree files would be overwritten by checkout
在IDEA中进行分支切换时,出现如此错误,导致无法正常切换:error: The following untracked working tree files would be overwritten ...