首页 > 其他分享 >[NOI2010] 超级钢琴 题解

[NOI2010] 超级钢琴 题解

时间:2023-10-27 18:15:15浏览次数:28  
标签:Node Right int 题解 Value 钢琴 NOI2010 Now Left

[NOI2010] 超级钢琴 题解

说点闲话

原本不想写这个题解的

但是看到我的代码居然长度为2048B->刚好2KiB,然后还跟题号相同QAQ

题目翻译

给你一段序列,求出其中从第\(1\)大到第\(k\)大的子区间的和。

思路解析

首先可以想到一个简单的暴力,对于每一个区间开头\(i\),和区间结尾\(j\),都求出其值,然后排序,将前\(k\)大的值加起来即可。

但是这个暴力时间复杂度太大了,是\(O(n^2log_n)\),显然我们是不能接受的,但是分析数据范围之后,我们就知道在\(O(nlog_n)\)的时间以内应该就是正解。那么回想我们的暴力,我们是将区间开头和区间结尾各自都枚举了一遍,但是如果我们只枚举一个呢。所以我们想到优化,先记录区间的前缀和,方便求出各个区间的和,就是枚举以各个\(StLeft\)为开头的区间,求出\(StLeft+L-1\)到\(StLeft+R-1\)中前缀和最大的一个(St表/线段树维护),减去\(StLeft-1\)的前缀和,即可得到以\(StLeft\)开头,合法的区间中,区间和最大的一个(注意处理数组越界问题)。

然后将所有的五元组塞入一个堆里面,从堆中取\(k\)次值,每次取出之后将答案累计进去。但是如果只是单纯地这么做正确性是不能保证的,因为很容易想到可能有两个\(StLeft\)为同一个值,而\(MaxPos\)不同的五元组都需要被计入答案。所以我们还要做的是将取出来的五元组分裂,然后再塞回堆里面。只需要将五元组的\(Left,Right\)按\(MaxPos\)分裂为两部分,之后再对新的两个五元组求出\(MaxPos\)塞回堆里面即可。具体而言,将原本的\(Left,Right\)分裂为\(Left,MaxPos-1\)和\(MaxPos+1,Right\)(记得特判,防止越界)。

关于Debug

我做这道题的时候挺顺的,交的时候一遍就过了。

可能比较需要注意的是:

1)初始塞五元组的时候,防止\(Left,Right\)越界

2)分裂的时候不要让新的五元组的\(Left>Right\)了

3)线段树不要写错了(我就是写错了线段树没过样例QAQ)

关于代码

#include <cstdio>
#include <cstring>
#include <queue>
#define MAXN 500010
using namespace std;
int OLine[MAXN],Sum[MAXN],Total=0,RetP=0,RetV=0,n,k,l,r;
long long Ans=0;
struct O{
	int Value,StLeft,Left,Right,Position;
};
bool operator<(O a,O b){
	return a.Value<b.Value;
}
priority_queue <O> Q;
struct N{
	int Left,Right;
	int Value,Pos;
	int LeftN,RightN;
}Node[MAXN<<2];
void Build(int Left,int Right){
	Total++;
	Node[Total].Left=Left;
	Node[Total].Right=Right;
	if(Left==Right){Node[Total].Value=Sum[Left]; Node[Total].Pos=Left; return;}
	int Now=Total,Mid=(Left+Right)>>1;
	Node[Now].LeftN=Total+1;Build(Left,Mid);
	Node[Now].RightN=Total+1;Build(Mid+1,Right);
	Node[Now].Value=Node[Node[Now].LeftN].Value,Node[Now].Pos=Node[Node[Now].LeftN].Pos;
	if(Node[Node[Now].RightN].Value>Node[Now].Value){
		Node[Now].Value=Node[Node[Now].RightN].Value,Node[Now].Pos=Node[Node[Now].RightN].Pos;
	}
}
void Query(int Now,int Left,int Right){
	if(Node[Now].Left>=Left&&Node[Now].Right<=Right){if(Node[Now].Value>RetV){RetV=Node[Now].Value;RetP=Node[Now].Pos;}return;}
	else if(Node[Now].Left>Right||Node[Now].Right<Left){return;}
	else{
		Query(Node[Now].LeftN,Left,Right);
		Query(Node[Now].RightN,Left,Right); 
	}
}
O Make(int StL,int Left,int Right){
	O Ret;
	Ret.StLeft=StL;
	Ret.Left=Left;
	Ret.Right=Right;
	RetP=-1<<30,RetV=-1<<30;
	Query(1,Left,Right);
	Ret.Position=RetP;
	Ret.Value=RetV;
	Ret.Value-=Sum[StL-1];
	return Ret;
}
int main(){
	scanf("%d%d%d%d",&n,&k,&l,&r);
	Sum[0]=0;
	for(int i=1;i<=n;i++){
		scanf("%d",&OLine[i]);
		Sum[i]=Sum[i-1]+OLine[i];
	}
	Build(1,n);
	for(int i=1;i<=n;i++){
		int LL,RR;
		if(i+l-1<=n) LL=i+l-1;
		else{break;}
		if(i+r-1<=n) RR=i+r-1;
		else RR=n;
		Q.push(Make(i,LL,RR));
	}
	while(k--){
		Ans+=Q.top().Value;
		int P=Q.top().Position;
		int LL=Q.top().Left,RR=Q.top().Right,STLL=Q.top().StLeft;
		Q.pop();
		if(P!=LL) Q.push(Make(STLL,LL,P-1));
		if(P!=RR) Q.push(Make(STLL,P+1,RR));
	}
	printf("%lld",Ans);
	return 0;
}

标签:Node,Right,int,题解,Value,钢琴,NOI2010,Now,Left
From: https://www.cnblogs.com/Ehundategh/p/17792919.html

相关文章

  • 2023 CSP-J2 T1,2,3题解
    今年的\(CSP−J\)对本蒟蒻来说有点难度。。。A[CSP-J2023]小苹果题目描述小Y的桌子上放着\(n\)个苹果从左到右排成一列,编号为从\(1\)到\(n\)。小苞是小Y的好朋友,每天她都会从中拿走一些苹果。每天在拿的时候,小苞都是从左侧第\(1\)个苹果开始、每隔\(2\)个......
  • [TJOI2013] 松鼠聚会 题解
    [TJOI2013]松鼠聚会题解切比雪夫距离切比雪夫距离指的是在平面上的两个点\((x_1,y_1)\),\((x_2,y_2)\)之间横纵坐标之差绝对值中的大者。用公式表示则是\(f(a,b)=max(|x_a-x_b|,|y_a-y_b|)\)。切比雪夫距离与曼哈顿距离之间可以相互转换切比雪夫—>曼哈顿:\((x_1,y_1)\),\((x......
  • [NOIP 2013提高组]货车运输 题解
    [NOIP2013提高组]货车运输题解前置知识Kruskal重构树(内含讲解)+任意一种LCA题目翻译\(n\)座城市,\(m\)条道路,\(q\)次询问,每次求两个点\(x,y\)之间所有路径的最小值的最大值。题目分析其实学了Kruskal重构树差不多看到这个题目就知道怎么写了。其实就是Kruskal重构树的板子,......
  • 问题解决
    pip源问题解决使用pip安装pytorch出现WARNING:Retrying(Retry(total=4,connect=None,read=None,redirect=None,status=None))报错使用换源解决问题pip3configlistpip3configsetglobal.index-urlhttps://mirrors.aliyun.com/pypi/simple/pip3configlist国内......
  • 第四章苏格拉底问答、实践过程截图、遇到问题解决问题截图,代码链接
    代码#include<stdio.h>#include<stdlib.h>#include<pthread.h>#defineN4intA[N][N],sum[N];void*func(voidarg){intj,row;pthread_ttid=pthread_self();row=(int)arg;printf("Thread%d[%lu]computessumofrow%d\n"......
  • Python打不开问题解决方案大全
    在使用Python进行编程开发的过程中,我们不可避免会遇到Python打不开的问题。这些问题可能是由于环境配置、包管理和依赖文件等问题所导致的,但不管是何种原因,我们都需要解决它们才能顺利地进行工作。本文将从多个方面为大家详细介绍Python打不开问题的解决方法。一、Python环境配......
  • Acwing393. 雇佣收银员 题解 差分约束
    题目链接:https://www.acwing.com/problem/content/description/395/解题思路:差分约束。为了方便起见,定义第\(i\)个时间段为\(i-1:00\)到\(i:00\)首先,为了方便开一个额外的点,令\(R_i\)对应为题目中的\(R(i+1)\),即\(R_i\)表示\(i-1:00\)到\(i:00\)这个时间段的最小需求......
  • AnyCAD程序无法启动的问题解决方法
    在某些电脑上会出现基于AnyCAD开发的程序无法启动的问题,如:System-ArgumentEcception:Pleasecheckthedependendes解决方法安装最新的VS运行时库,如VS2022:微软官方下载地址:x64:vc_redist.x64.exeSystem.AccessViolationException:"Attemptedtoreadorwriteprotectedmemor......
  • CF777题解
    分析先对每一列都做DP寻找极长单调不降区间,能够得到若干极长单调不降区间,只要询问的区间是这些区间的子区间,那么说明在这个区间内必有一列的这个区间是单调不降的。思考如何快速判断子区间。用\(f_{x}\)表示以\(x\)为所有左端点为\(x\)的区间的右端点最大值,那么对于......
  • ThinkPad OneLink+ Dock扩展坞 多屏幕 黑屏 问题解决
    我的机器是ThinkpadnewS2,扩展坞是ThinkPadOneLink+Dock,操作系统是win10原版。由于工作原因,把笔记本当台式机用。接了两台1920*1080的显示器。用了一段时间后,两台显示器中的其中一台显示器,黑屏,在win10的显示界面,应当有三台显示器,但实际只有两台。类似下图出现这个问题,毫无......