首页 > 编程语言 >[题解][2022年江西省大学生程序设计竞赛] Remove and append

[题解][2022年江西省大学生程序设计竞赛] Remove and append

时间:2024-04-12 22:22:20浏览次数:26  
标签:数组 val int 题解 合并 pos Remove 个数 2022

题目描述

给定一个包含n个整数的数组a。定义一个操作如下:
从数组a中选择k个整数,将它们删除,并将它们的和追加到数组末尾。
如果数组A比数组B(长度相同)字典序大,那么在A和B第一次不同的位置上,A的数字比B对应位置上的数字要大。例如,[0, 1, 14, 0]比[0, 1, 5, 6]字典序大,因为它们在第三个数字上第一次不同,而14比5大。字典序最大的数组意味着该数组在长度相同的情况下比其他任何数组都要大。
请输出在执行给定操作p次后的字典序最大的数组。

题解

考虑到每次合并会相当于减少k个数,并在末尾增加1个数。则数组会减少k-1个数。
在执行p次操作后,剩余的数字个数为rest = n -(k-1)* p。没有参与合并操作的数字个数为old = max(0,n - k *p)。
现在分别处理不参与合并的数列和参与合并的数列。

  • 不参与合并:相当于计算原数列长度为k的最大字典序子序列。
  1. 设查找范围为(l,r),查找数列长度为k。
  2. 每次先找到该范围的一个最大值(val)及最大值的下标(pos),用线段树维护。
  3. 若r - pos > k - 1,即在该最大值之后选数可以选到k个,便在该位置之后递归。
  4. 否则,该最大值之后的数全部选择也达不到k个,就需要在该位置之前选k - 1 - (r - pos)个数,并在其之后选r - pos个数。
  • 由于题目要求字典序最大,可知所有合并的数组成的数列一定是单调不上升的。因为一旦有数大于在它前面的数,那么把二者互换位置就可以使字典序更大。
    因此可以通过排序和堆,先将大的数合并放到较前的位置,小的数合并放到后面的位置。
    需要特殊考虑合并生成的第一个数:该数可能不止由k个数合并而成,若p值较大,第一个数可能经历多次合并,由(k - 1)* re + 1个数合并得到,re = p - (rest - old)+ 1。

代码

点击查看代码
#include<bits/stdc++.h>
#define int  long long
using namespace std;
const int N=3e5+7;
int n,k,p;
int a[N],v[N];
priority_queue<int>q;
struct MaxNumber{
	int pos,val;
};
struct SegmentTree{
	int l,r;
	MaxNumber num;
	#define l(x) tree[x].l
	#define r(x) tree[x].r
	#define num(x) tree[x].num
	#define val(x) tree[x].num.val
	#define pos(x) tree[x].num.pos
}tree[N<<2];
void build(int p,int l,int r){
	l(p)=l,r(p)=r;
	if(l==r){val(p)=a[l];pos(p)=l;return;}
	int mid=l+r>>1;
	build(p*2,l,mid),build(p*2+1,mid+1,r);
	if(val(p*2)>=val(p*2+1))val(p)=val(p*2),pos(p)=pos(p*2);
	else val(p)=val(p*2+1),pos(p)=pos(p*2+1); 
}
MaxNumber ask(int p,int l,int r){
	if(l<=l(p)&&r>=r(p))return num(p);
	int mid=l(p)+r(p)>>1;
	MaxNumber L,R;
	L.val=0,R.val=0;
	if(l<=mid)L=ask(p*2,l,r);
	if(r>mid)R=ask(p*2+1,l,r);
	if(L.val>=R.val)return L;
	else return R;
}
void check(int l,int r,int cnt){
	if(l>r)return;
	MaxNumber x=ask(1,l,r);
	v[x.pos]=1;	
	if(cnt<=1)return;
	int behind=r-x.pos;
	if(behind>=cnt-1)check(x.pos+1,r,cnt-1);
	else{
		int front=cnt-1-behind;
		check(l,x.pos-1,front);
		check(x.pos+1,r,behind);
	}
}
void clear(){
	for(int i=1;i<=n;i++)a[i]=v[i]=0;
	while(q.size())q.pop();
}
signed main(){
	int t;
	cin>>t;
	while(t--){
		int sum=0;
		cin>>n>>k>>p;
		for(int i=1;i<=n;i++)cin>>a[i],sum+=a[i];
		if(n==(k-1)*p+1){
			cout<<sum<<endl;
			continue;
		}
		int rest=n-(k-1)*p;
		int old=max(n-p*k,0ll);	
		int ne=rest-old;
		build(1,1,n);
		if(old>0)check(1,n,old);
		for(int i=1;i<=n;i++){
			if(v[i])cout<<a[i]<<" ";
			else q.push(a[i]);
		}
		int re=p-ne+1;
		int first=0;
		for(int i=1;i<=re*(k-1)+1;i++){
			int x=q.top();
			q.pop();
			first+=x;
		}
		cout<<first<<" ";
		for(int i=2;i<=ne;i++){
			int ans=0;
			for(int j=1;j<=k;j++){
				int x=q.top();
				q.pop();
				ans+=x;
			}
			cout<<ans<<" ";
		}
		cout<<endl;
		clear();
	}
}

标签:数组,val,int,题解,合并,pos,Remove,个数,2022
From: https://www.cnblogs.com/zwzww/p/18132250

相关文章

  • C++算法题解 - 递归实现排列型枚举 - 递归法 (图文) (递归搜索树)
    题目:递归实现排列型枚举把1∼n这n个整数排成一行后随机打乱顺序,输出所有可能的次序。输入格式一个整数n。输出格式按照从小到大的顺序输出所有方案,每行1个。首先,同一行相邻两个数用一个空格隔开。其次,对于两个不同的行,对应下标的数一一比较,字典序较小的排在前面。数据......
  • [题解] [洛谷P7883] 平面最近点对(加强版)
    [洛谷P1429]平面最近点对(加强版)题目描述给定平面上的\(n\)个点,求其中距离最小的两个点之间的距离。输入格式第一行:\(n\),保证\(2\leqn\leq200000\)。接下来\(n\)行,每行两个实数:\(x,y\),表示一个点的横坐标和纵坐标,中间用一个空格隔开。输出格式仅一行,一个实数......
  • atcoder beginer 347 (abc347) D E 题解
     D就是二进制下,哪些位置有重合(两个1),哪些位置没有重合(1个1,1个0),剩下的都是0。xor的结果<2^60,就是小于60位(二进制下)。注意要有要求两个数需要是2^60,于是要有大小的判断,因为有的a,b会2^60,但是按照题目要求,这个情况不行。比如xor的结果,60位都是1,然后a、b各有60个1,那么需要有30个1......
  • atcoder beginer 348 (abc348) D E F 题解
     E非常经典的树上操作(树上DP)。父节点到某个子节点,值是如何变化的。1#include<cstdio>2#include<cstdlib>3#include<cstring>4#include<cmath>5#include<cstdbool>6#include<string>7#include<algorithm>8#include<iost......
  • 2024.4.10华为暑期实习笔试题解尝试1~2
    题目在4.10华为暑期实习笔试题解努力开摆的小鱼2024-04-10T1简单难度,按照题意顺着写就可以n=int(input())#表示计费日志的条数lst=[]#去重后的日志ss=set()#为了去重foriinrange(n):s=tuple(input().split(","))t=s[0]+s[1]+s[2]#......
  • 题解:P10320 勇气(Courage)
    P10320勇气(Courage)推导过程本题是一道数学题,重点是如何推导出正确式子。首先,先特判几个特殊点:当\(n>=2\)且\(x=2\)时,是不存在解的,战斗力无论何时都不会超过\(2^{n}\)。当\(x\)不强化就以大于\(2^{n}\)。当\(x\)第一次强化达到\(x^{2}\)时,大于\(2^{n}\)......
  • P4211 LCA 题解
    前置知识:树剖、差分题意给定一个\(n\)个节点的有根树树,根为\(1\)。有\(m\)个询问,每个询问给定\(l,r,z\),求\(\sum\limits_{i=l}^rdep[\textrm{LCA}(i,z)]\)。其中\(dep[x]\)表示\(x\)的深度,有\(dep[1]=1\)。题解式子中的\(dep\)不太好算,考虑转化成形式化......
  • [题解] [NOIP2011] 聪明的质检员
    [NOIP2011]聪明的质监员题目描述小T是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有\(n\)个矿石,从\(1\)到\(n\)逐一编号,每个矿石都有自己的重量\(w_i\)以及价值\(v_i\)。检验矿产的流程是:给定\(m\)个区间\([l_i,r_i]\);选出一个参数\(W\);对......
  • Qt程序加载Qt platform plugin 'xcb' 出错问题解决
    1.Qt程序运行环境ubuntu16.04Qt5.12.3Qt可执行程序编译后运行Qt可执行程序后出现报错报错内容:qt.qpa.plugin:CouldnotloadtheQtplatformplugin"xcb"in""eventhoughitwasfound.ThisapplicationfailedtostartbecausenoQtplatformplugincouldbe......
  • [题解][2022江西省程序设计竞赛] Graphic Game
    题目描述Cirno被推荐了一个游戏,她决定今天和大妖精一起玩。最初,有一个包含2×n个顶点和m条边的图。在每一轮中,Cirno和大妖精都必须选择一个不同的顶点。所选顶点的度数必须相同。然后,Cirno和大妖精将从图中移除它们。现在Cirno想知道是否有办法从给定的图中移除所有顶点。如果......