P11118 [ROI 2024 Day 2] 无人机比赛 题解

news2024/11/5 2:42:26

Description

n n n 架无人机参与比赛,第 i i i 架无人机飞过一个单位距离需 t i t_i ti 秒。

赛道为一条直线,上面有 m m m 个存档点,第 i i i 个存档点距起点 s i s_i si 个单位长度,保证 s i + 1 > s i s_{i+1}>s_i si+1>si

一共有 n n n 场比赛,第 k k k 场比赛有前 k k k 架无人机参加,比赛按如下方式进行。

定义一个阶段为当前还未完赛的所有无人机从其存档点开始飞行,直到有一架无人机到达了下一个存档点,我们称这架无人机为此阶段的赢家。若有多架无人机同时到达,则编号最小的为赢家。

该阶段结束后,所有非赢家的无人机将被传送回此阶段开始时其所在的存档点,而赢家则更新其存档点。若赢家此时到达了第 m m m 个存档点,那么它将完赛,后面的阶段都不参加。

当所有无人机都完赛时,那么这场比赛就结束了。

你需要对于这 n n n 场比赛中的每一场,分别求出比赛中所有无人机的传送次数之和。

Solution

依题意得一个阶段中只有赢家改变存档点,对非赢家造成传送,而非赢家之间的相对位置都不改变,不会互相造成传送。

于是总传送次数可以拆成两两之间所造成的贡献之和,并且这只与它们两有多少个阶段输赢不同有关,即对于 i , j i,j i,j,两机互相造成的贡献为 i , j i,j i,j 中第一架无人机完赛时,已经经过了多少个阶段。

对于一架无人机 i i i,我们定义 w j = ( s j − s j − 1 ) × t i w_j=(s_j-s_{j-1})\times t_i wj=(sjsj1)×ti

那么对于 i , j i,j i,j 算贡献,可以通过归并 i , j i,j i,j 的两个 w w w 序列来求出。然而 w w w 并不有序,但我们可以通过 UR #26 石子合并 中的结论,即对于同一序列的 w w w,若 w i + 1 ≤ w i w_{i+1}\le w_i wi+1wi 那么 w i + 1 w_{i+1} wi+1 会在 w i w_i wi 弹出后紧接地弹出,在归并后的数组中相邻。

而同一组中的 w w w 大小关系与 t t t 无关,与 s s s 的差分数组有关,所以可以对 s s s 的差分数组进行操作,将会紧邻弹出的数合在一起,设其总共有 k k k 个这样的段。每个段计 a i , b i a_i,b_i ai,bi,表示这一段段头的值以及这一段的长度。

因为 a i a_i ai 是严格递增的,那么由于 a 1 + a 2 + ⋯ + a k = s m ≤ 1.5 × 1 0 5 a_1+a_2+\cdots+a_k=s_m\le1.5\times10^5 a1+a2++ak=sm1.5×105,所以 k k k 的大小是 O ( V ) O(\sqrt{V}) O(V ) 的, V V V 1.5 × 1 0 5 1.5\times10^5 1.5×105 级别的。

回到对 i , j ( i < j ) i,j(i<j) i,j(i<j) 算贡献,发现比较好算了:

  • t i ≤ t j t_i\le t_j titj,那么 i i i 先完赛,先加上 m m m 的贡献,即 i i i j j j 造成的贡献。 j j j i i i 造成的贡献就是看在 i i i 完赛时, j j j 到了第几个存档点,也就是找到最大的 x x x 使得 a k × t i > a x × t j a_k\times t_i>a_x\times t_j ak×ti>ax×tj,然后加上 b 1 + b 2 + ⋯ + b x b_1+b_2+\cdots+b_x b1+b2++bx 的贡献。

  • t i > t j t_i>t_j ti>tj,那么 j j j 先完赛,同样先加上 m m m 的贡献。然后找到最大的 x x x 使得 a x × t i ≤ a k × t j a_x\times t_i\le a_k\times t_j ax×tiak×tj,同样加上 b 1 + ⋯ b x b_1+\cdots b_x b1+bx 的贡献,注意是 小于等于,因为 i < j i<j i<j,所以当两人用时相等时赢家是 i i i

x x x 用二分,那么至此我们用 O ( n 2 log ⁡ V ) O(n^2\log\sqrt{V}) O(n2logV ) 的复杂度解决了问题,比暴力分多 10 10 10 分,可喜可贺。

那么怎么继续优化呢?

考虑上扫描线,我们从小到大扫 i i i,对于每一个可能的 x x x,先二分找到 j j j 的限制(两种情况),再对这两段区间加上 b x b_x bx,注意我们已经把贡献分成了 m m m b 1 + ⋯ + b x b_1+\cdots+b_x b1++bx

计算答案就是扫到 j j j 时,取出其在线段树内的值,然后加上 j × ( j − 1 ) 2 × m \dfrac{j\times(j-1)}{2}\times m 2j×(j1)×m 的贡献。

注意线段树上维护的是 离散后的 t t t 的值,二分也是找离散后的值,同时要 先算贡献再查值,不然若 t i = t j t_i=t_j ti=tj 时会重复算贡献。

现在时间复杂度变为了 O ( n V ( log ⁡ n + log ⁡ n ) ) O(n\sqrt{V}(\log n+\log n)) O(nV (logn+logn)),前面的 log ⁡ \log log 是二分,后面的 log ⁡ \log log 是区间修改,单点查询的线段树。但这个复杂度跑不过去,需要进一步优化。

注意到区间修改有 O ( n V ) O(n\sqrt{V}) O(nV ) 级别,而询问只有 O ( n ) O(n) O(n) 级别,那么可以用区间修改 O ( 1 ) O(1) O(1),单点查询 O ( n ) O(\sqrt{n}) O(n ) 的分块来平衡复杂度,具体的,维护每个点和每个块的差分数组,修改时修改两个点和两个块的值,查询即查询差分数组的前缀和。

但二分的 O ( log ⁡ n ) O(\log n) O(logn) 还没去掉,观察到当 x x x 相同时, i i i 递增时,其对应 j j j 的限制也递增, i , j i,j i,j 是离散后 t t t 数组的下标。那么可以预处理出 t a g i , x tag_{i,x} tagi,x,表示二分出来的限制,用双指针维护做到时间 O ( n V ) O(n\sqrt{V}) O(nV ),空间 O ( n V ) O(n\sqrt{V}) O(nV )。注意两种限制的双指针有所不同,细节较多。

这个题就用时间 O ( n ( V + n ) ) O(n(\sqrt{V}+\sqrt{n})) O(n(V +n )),空间 O ( n V ) O(n\sqrt{V}) O(nV ) 的复杂度做完了,吗?

实际上 k k k 的极限并不是 1.5 × 1 0 5 \sqrt{1.5\times10^5} 1.5×105 ,而是 550 550 550 。所以开两个 t a g tag tag 会爆空间,不过只要先处理一种,算贡献,再处理另外一种,算贡献就可以了。

时间上有略微卡常,只需在求 t a g tag tag 时使访问较为连续即可,先枚 i i i,再枚 x x x

还有一些细节具体见代码。

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
int n,m,k,cnt,len;
int t[150010],s[150010],tt[150010],id[150010];
int tag[150010][560];
int st[150010],hd;
int a[560],b[560];
ll fin1[150010],fin2[560],ans[150010];
void init(){
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		cin>>t[i],tt[i]=t[i];
	}
	sort(tt+1,tt+1+n);
	cnt=unique(tt+1,tt+1+n)-tt-1;
	len=sqrt(cnt)+1;
	for(int i=1;i<=n;i++){
		t[i]=lower_bound(tt+1,tt+1+cnt,t[i])-tt;
	}
	for(int i=1;i<=cnt+1;i++){
		id[i]=(i-1)/len+1;
	}
	for(int i=1;i<=m;i++){
		cin>>s[i];
	}
	for(int i=m;i;i--){
		while(hd&&s[st[hd]]-s[st[hd]-1]<=s[i]-s[i-1]) hd--;
		st[++hd]=i;
	}
	st[0]=m+1;
	for(int i=hd;i;i--){
		a[++k]=s[st[i]]-s[st[i]-1];
		b[k]=st[i-1]-st[i];
	}
}
void update(int l,int r,ll v){  //O(1)更新
	fin1[l]+=v,fin1[r+1]-=v;
	fin2[id[l]]+=v,fin2[id[r+1]]-=v;
}
ll query(int x){  //O(sqrt(n)) 查询
	ll sum=0;
	for(int i=1;i<id[x];i++){
		sum+=fin2[i];
	}
	for(int i=(id[x]-1)*len+1;i<=x;i++){
		sum+=fin1[i];
	}
	return sum;
}
void pres1(){  //ti<=tj
	for(int j=1;j<=cnt;j++){
		for(int i=1;i<=k;i++){
			int fl=tag[j-1][i];
			while(1){
				tag[j][i]=fl;
				if(fl+1>cnt||(ll)tt[j]*a[k]<=(ll)tt[fl+1]*a[i]) break;
				fl++;
			}
		}
	}
}
void pres2(){  //ti>tj,两个双指针细节多,一定要理解充分
	for(int j=1;j<=cnt;j++){
		for(int i=1;i<=k;i++){
			int fl=tag[j-1][i];
			while(1){
				if((ll)tt[j]*a[i]<=(ll)a[k]*tt[fl]){
					tag[j][i]=fl;
					break;
				}
				fl++;
			}
		}
	}
}
void solve(){
	pres1();
	for(int i=1;i<=n;i++){
		ans[i]=query(t[i]);
		for(int j=1;j<=k;j++){
			if(tag[t[i]][j]>=t[i]){
				update(t[i],tag[t[i]][j],b[j]);
			}
		}
	}
	pres2();
	for(int i=1;i<=cnt;i++) fin1[i]=0;  //记得清空分块
	for(int i=1;i<=id[cnt+1];i++) fin2[i]=0;
	for(int i=1;i<=n;i++){
		ans[i]+=ans[i-1]+query(t[i]);
		cout<<ans[i]+(ll)i*(i-1)/2*m<<'\n';
		for(int j=1;j<=k;j++){
			if(tag[t[i]][j]<t[i]){
				update(tag[t[i]][j],t[i]-1,b[j]);
			}
		}
	}
}
int main(){
	ios::sync_with_stdio(0);
	cin.tie(nullptr);
	init();
	solve();
	return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2232271.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

老板电器芯邦CBM7332触摸式净化水槽硬件和程序

老板电器净化水槽是一款集水槽与食材净化功能于一体的创新产品&#xff0c;旨在为你提供更健康、便捷的厨房体验。 老板电器净化水槽具有以下好处和优点&#xff1a; 一、健康保障 1. 高效净化&#xff1a;能够有效去除食材中的农药残留、细菌、激素等有害物质&#xff0c;为…

Python脚本批量给文件添加前缀(超简单,超实用)

文章目录 讲个故事说个问题写个方案一、安装Python脚本环境二、新建文件夹和文件三、编写源代码四、详细操作视频五、总结 讲个故事 有一天&#xff0c;我的老板丢给了我一个压缩包&#xff0c;轻描淡写的来了句&#xff0c;把包里的文件名字开头统统加上公司名字&#xff0c;…

深度学习之经典网络-AlexNet详解

AlexNet 是一种经典的卷积神经网络&#xff08;CNN&#xff09;架构&#xff0c;在 2012 年的 ImageNet 大规模视觉识别挑战赛&#xff08;ILSVRC&#xff09;中表现优异&#xff0c;将 CNN 引入深度学习的新时代。AlexNet 的设计在多方面改进了卷积神经网络的架构&#xff0c;…

Android亮屏Job的功耗优化方案

摘要: Job运行时会带来持锁的现象,目前灭屏放电Job的锁托管已经有doze和绿盟标准监管,但是亮屏时仍旧存在过长的持锁现象,故为了优化功耗和不影响用户体验下,新增亮屏放电下如果满足冻结和已运行过一次Job,则进行job限制,当非冻结时恢复的策略 1.现象: (gms_schedu…

Linux版更新流程

一.下载更新包 下载地址&#xff1a;https://www.nvisual.com/%e4%b8%8b%e8%bd%bd/ 二.更新包组成 更新包由三部分组成&#xff1a; 前端更新包&#xff1a;压缩的ZIP文件&#xff0c;例如&#xff1a;dist-2.2.26-20231227.zip (2.2.26是版本号 20231227是发布日期)后端更…

Java环境下配置环境(jar包)并连接mysql数据库

目录 jar包下载 配置 简单连接数据库 一、注册驱动&#xff08;jdk6以后会自动注册&#xff09; 二、连接对应的数据库 以前学习数据库就只是操作数据库&#xff0c;根本不知道该怎么和软件交互&#xff0c;将存储的数据读到软件中去&#xff0c;最近学习了Java连接数据库…

鸿蒙网络编程系列42-仓颉版域名解析示例

1. 域名解析简介 域名解析是网络开发中经常使用的功能之一&#xff0c;特别是对于当前版本的鸿蒙API&#xff0c;使用TCP或者UDP等网络协议通讯时&#xff0c;只能使用确定的IP地址进行绑定或者发送消息&#xff0c;还不支持直接使用域名&#xff0c;所以&#xff0c;通过域名…

第15课 算法(下)

掌握冒泡排序、选择排序、插入排序、顺序查找、对分查找的的基本原理&#xff0c;并能使用这些算法编写简单的Python程序。 一、冒泡排序 1、冒泡排序的概念 冒泡排序是最简单的排序算法&#xff0c;是在一列数据中把较大&#xff08;或较小&#xff09;的数据逐次向右推移的…

Netty 强大的 ByteBuf

Netty 强大的 ByteBuf Netty ByteBuf功能可以类比NIO 中 ByteBuffer&#xff0c;那为什么不直接使用NIO 中ByteBuffer? 主要是易用性和扩展性一些方面&#xff0c;有点可以肯定&#xff0c;Netty 基于NIO实现的&#xff0c;底层肯定用了ByteBuffer 。 jdk Buffer API 复杂性…

从安装到实战:Spring Boot与kafka终极整合指南

docker环境下部署kafka 前置条件 Apache Kafka 自 2.8.0 版本开始引入了不依赖 Zookeeper 的“Kafka Raft Metadata Mode”&#xff0c;本文章依然使用Zookeeper 作为集群管理的插件。 #拉去zookeeper镜像docker pull wurstmeister/zookeeper#运行zookeeper容器docker run -…

【Kettle的安装与使用】使用Kettle实现mysql和hive的数据传输(使用Kettle将mysql数据导入hive、将hive数据导入mysql)

文章目录 一、安装1、解压2、修改字符集3、启动 二、实战1、将hive数据导入mysql2、将mysql数据导入到hive 一、安装 Kettle的安装包在文章结尾 1、解压 在windows中解压到一个非中文路径下 2、修改字符集 修改 spoon.bat 文件 "-Dfile.encodingUTF-8"3、启动…

如何看待AI技术的应用前景?

文章目录 如何看待AI技术的应用前景引言AI技术的现状1. AI的定义与分类2. 当前AI技术的应用领域 AI技术的应用前景1. 经济效益2. 社会影响3. 技术进步 AI技术应用面临的挑战1. 数据隐私与安全2. 可解释性与信任3. 技能短缺与就业影响 AI技术的未来发展方向1. 人工智能的伦理与法…

PyQt5实战——UTF-8编码器UI页面设计以及按钮连接(五)

个人博客&#xff1a;苏三有春的博客 系类往期文章&#xff1a; PyQt5实战——多脚本集合包&#xff0c;前言与环境配置&#xff08;一&#xff09; PyQt5实战——多脚本集合包&#xff0c;UI以及工程布局&#xff08;二&#xff09; PyQt5实战——多脚本集合包&#xff0c;程序…

快速入门CSS

欢迎关注个人主页&#xff1a;逸狼 创造不易&#xff0c;可以点点赞吗 如有错误&#xff0c;欢迎指出~ 目录 CSS css的三种引入方式 css书写规范 选择器分类 标签选择器 class选择器 id选择器 复合选择器 通配符选择器 color颜色设置 border边框设置 width/heigth 内/外边距 C…

【基础】os模块

前言 1、os是operation system&#xff08;操作系统&#xff09;的缩写&#xff1b;os模块就是python对操作系统操作接口的封装。os模块提供了多数操作系统的功能接口函数。&#xff08;OS模块提供了与操作系统进行交互的函数&#xff09; 2、操作系统属于Python的标准实用程…

Linux---cp命令

Linux cp 命令 | 菜鸟教程 (runoob.com) 命令作用&#xff1a; cp命令主要用于复制文件或目录 语法: cp [options] source dest cp [选项] 源文件 目标文件 source:要复制的文件或目录的名称 dest:复制后的文件或目录的名称 注意&#xff1a;用户使用该指令复制目录时&…

MyBatis-Plus快速入门:从安装到第一个Demo

一、前言 在现代 Java 应用程序中&#xff0c;数据访问层的效率与简洁性至关重要。MyBatis-Plus 作为 MyBatis 的增强工具&#xff0c;旨在简化常见的数据操作&#xff0c;提升开发效率。它提供了丰富的功能&#xff0c;如自动生成 SQL、条件构造器和简单易用的 CRUD 操作&…

【android12】【AHandler】【3.AHandler原理篇AHandler类方法全解】

AHandler系列 【android12】【AHandler】【1.AHandler异步无回复消息原理篇】-CSDN博客 【android12】【AHandler】【2.AHandler异步回复消息原理篇】-CSDN博客 其他系列 本人系列文章-CSDN博客 1.简介 前面两篇我们主要介绍了有回复和无回复的消息的使用方法和源码解析&a…

美发系统——职员绩效和提成——调试过程

一、学会通过现象看本质 首先&#xff0c;通过现象看本质能够让技术研究者更深入地理解问题。在面对技术故障或挑战时&#xff0c;表面的现象往往只是冰山一角&#xff0c;如果只关注表象&#xff0c;可能会采取治标不治本的解决方法。而洞察本质则可以找到问题的根源&#xf…

记一次:Clickhouse同步mysql数据库

ClickHouse可以通过使用MaterializeMySQL引擎来实现与MySQL的数据同步。 前言&#xff1a;因为数据量比较大&#xff0c;既然要分库&#xff0c;为何不让clickhouse同步一下mysql数据库呢&#xff1f; 零、前期准备--mysql的查询和配置 1 查询mysql的配置状态 查询以下语句…