[THUPC 2024 初赛] 二进制 (树状数组单点删除+单点查询)(双堆模拟set)

题解

题目本身不难想

首先注意到所有查询的序列长度都是小于logn级别的

我们可以枚举序列长度len,然后用类似滑动窗口的方法,一次性预处理出每种字串的所有出现位置,也就是开N个set去维护所有的位置。预处理会进行O(logn)轮,每次需要O(n*logn)的时间复杂度初始化set并计算位置。总共复杂度O(nlog^2n),看一下时间限制6s,感觉可以过23333。

删除操作可以直接暴力,直接从每种字串的位置集合中删除所有被影响到的位置,然后再把删除后字符串合并产生的新的子串加入到set中,过程中需要支持O(logn)的单点删除和单点查询。

在set中,删除起始点在L~R之间子串信息,再插入起始点在L到x-1的新构成的子串的信息

删除操作最多O(n/logn)次,每次直接暴力就是O(log^2n),总共复杂度O(nlogn)

接下来就是一些小问题,如何维护单点删除、单点查询的序列呢?

首先我们肯定不会去真正的移动序列,保留原始的输入01序列

可以想到用set去维护当前存在的每个坐标,但是支持查询第k个坐标的话得手写平衡树

也可以想到用线段树或者树状数组维护每个位置的存在信息,在线段树或者树状数组上二分来查询删除后的序列中的第k个坐标的真实位置。

这里使用树状数组

树状数组二分类似于倍增查询LCA的思想,十分易懂。

然后我们迅速写完整个内容,交一发,发现TLE了

看一下复杂度,发现瓶颈在于预处理,于是我们把初始化中对每个位置都进行树状数组二分,替换为直接使用当前位置存在信息数组进行处理,这样预处理中计算坐标的部分就变成O(n)了

但是仍然TLE了

现在瓶颈仍然是预处理,如果C++支持对有序序列O(n)建立set就好了

后来看了洛谷上题解的方法,才知道可以用两个优先队列来模拟set

由于我们只需要维护集合中的最小值以及集合的元素个数

使用两个堆,一个维护插入的内容,另一个维护删除的内容

当查询个数时,两个堆的大小相减即可。当查询最小值时,如果“删除堆”中的最小值与“插入堆”中的最小值相等,就两个一起pop掉,直到找到第一个“插入堆”中存在,但“删除堆”中不存在的元素即可。

(其实也可以用两个vector来模拟,因为对于每种子串,查询的次数只有一次,所以可以大胆排序再查询,这样初始化时间复杂度也是O(nlogn),查询删除子串的总时间复杂度是最坏O(nlog^2n)不过似乎也能过,因为sort在大部分都有序的情况下还是很快的)

改完之后,从6.18s变成了1.17s,发生了质的飞跃23333

有人可能会问,优先队列插入不也是O(logn)的吗,为什么会比set快这么多,因为预处理的过程中插入集合的内容是顺序的,根据小根堆的实现,只有当自己比父亲值小时,才会发生交换,所以在预处理建立小根堆的过程中是O(n)的,这样预处理的总复杂度就变成了O(nlogn),删除方面在理论上最坏时间复杂度也是O(nlog^2n)(假设所有的位置都集中在一种子串上,并且“删除堆”和“插入堆”差不多大)

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<set>
#include<queue>
using namespace std;
#define N 1000005
#define LOG 20
int n, n_real, now;
char ss[N];
// 树状数组维护单点删除与单点查询的序列
// 实际坐标->逻辑坐标(删除后的坐标) getsum
// 逻辑坐标->实际坐标  query   树状数组二分
int tra[N];
int getsum(int x)
{
	int ret=0;
	for(;x;x-=x&-x) ret+=tra[x];
	return ret;
}
void update(int x,int k)
{
	for(;x<=n;x+=x&-x)
		tra[x]+=k;
}
int query(int k)// 查询删除后序列的第k位置的实际坐标
{
	int ans=0,sum=0;
	for(int i=LOG;i>=0;i--){
		if(ans+(1<<i)<=n && sum+tra[ans+(1<<i)]<k){
			sum+=tra[ans+(1<<i)];
			ans+=(1<<i);
		}
	}
	return ans+1;
}
// a是原始数据,tmp是删除后的数组,b表示当前位是否存在(树状数组建立在b上)
bool a[N],tmp[N],b[N];
int pos[N];
void cal_tmp_all()
{
	int cnt=0;
	for(int i=1;i<=n;i++){
		if(b[i]){
			pos[++cnt]=i;
			tmp[cnt]=a[i];
		}
	}
}
void cal_tmp(int l,int r)
{
	l=max(1,l);r=min(r,n_real);
	for(int i=l;i<=r;i++){
		pos[i]=query(i);
		tmp[i]=a[pos[i]];
	}
}
priority_queue<int,vector<int>,greater<int> > S[N],D[N];
//set<int> S[N];
//set<int>::iterator it;
// 将起始点在l r之间,长度为len的数据加入到set或者从set中删除
void update_set(int l,int r,int len,bool flg)
{
	r=min(n_real,r+len-1);
	int lim_l= max(now,1<<(len-1)), lim_r= min(n,(1<<len)-1);
	int mask=(1<<len)-1;
	int tmp_value=0;
	for(int i=l;i<=r;i++){
		tmp_value=((tmp_value<<1)&mask)|tmp[i];
		if(i-l+1 >= len && tmp_value>=lim_l && tmp_value<=lim_r){
			if(flg)
				S[tmp_value].push(pos[i-len+1]);
			else
				D[tmp_value].push(pos[i-len+1]);
		}
	}
}
int main()
{
	scanf("%d",&n);n_real=n;
	scanf("%s",ss+1);
	for(int i=1;i<=n;i++){
		a[i]=int(ss[i]-'0');
		update(i,1);
		b[i]=1;
	}
	now=1;
	for(int len=1;n>>(len-1);len++){
		cal_tmp_all();
		update_set(1,n_real,len,1);
		//printf("start len:%d\n",len);
		for(;now<(1<<len);now++){
			//printf("now:%d\n",now);
			if(now>n)return 0;
			int siz = (int)S[now].size()-(int)D[now].size();
			if(!siz){
				printf("-1 0\n");
				continue;
			}
			while(!S[now].empty()&&!D[now].empty() && S[now].top()==D[now].top()){
				S[now].pop();
				D[now].pop();
			}
			int x=getsum(S[now].top());
			printf("%d %d\n",x,siz);
			int l=max(1,x-len+1),r=min(n_real,x+len-1);
			// 删除受影响的结果
			cal_tmp(l,r+len-1);
			update_set(l,r,len,0);
			// 删除对应的01序列
			for(int i=x;i<=r;i++){
				update(pos[i],-1);
				b[pos[i]]=0;
			}
			n_real-=len;
			// 添加新产生的序列结果
			cal_tmp(l,x-1+len-1);
			update_set(l,x-1,len,1);
			while(!S[now].empty())S[now].pop();
			while(!D[now].empty())D[now].pop();
		}
	}
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于谷歌模型gemini-pro 的开发的QT 对话项目

支持的功能&#xff0c;新建对话框&#xff0c;目前发现相关梯子不支持访问谷歌的api 的可能代理设置的不对&#xff0c; QNetworkAccessManager manager;// Set up your requestQNetworkRequest request;request.setUrl(QUrl("https://generativelanguage.googleapis.com…

这一平台只要把握住风口期,自己就能当老板!

我是电商珠珠 短视频渐渐走进大家的视野&#xff0c;改变了大家的日常娱乐方式。从19年开始&#xff0c;抖音开始发展电商平台-抖音小店。 在改变大家娱乐方式的同时&#xff0c;还将直播电商的热度掀了起来&#xff0c;由此改变了大家的购物方式&#xff0c;给大家带来了方便…

ansible-playbook实操之一键搭建lnmp+wordpress

目录 1、架构和准备&#xff1a; 2、配置nginx角色&#xff1a; 3、配置mariadb角色&#xff1a; 4、配置php角色&#xff1a; 5、配置完之后&#xff0c;写脚本调用roles 6、配置完之后浏览器搭建wordpress&#xff1a; 1、架构和准备&#xff1a; 操控节点&#xff1a;…

Echarts社区推荐

Apache Echarts官方示例中&#xff0c;有的demo并不能完全符合我们的需求&#xff0c;下面推荐几个Echarts社区&#xff0c;以便快速搭建项目。 1. isqqw 官方地址 &#xff1a;https://www.isqqw.com/ 2. makepie 官方地址 &#xff1a;https://www.makeapie.cn/echarts 3. P…

20231224解决outcommit_id.xml1 parser error Document is empty的问题

20231224解决outcommit_id.xml1 parser error Document is empty的问题 2023/12/24 18:13 在开发RK3399的Android10的时候&#xff0c;出现&#xff1a;rootrootrootroot-X99-Turbo:~/3TB/Rockchip_Android10.0_SDK_Release$ make installclean PLATFORM_VERSION_CODENAMEREL…

形态学处理

形态学处理的相关内容 &#xff08;1&#xff09;基于图像形态进行处理的一般方法 &#xff08;2&#xff09;这些处理方法基本是对二进制图像进行处理 &#xff08;3&#xff09;卷积核决定着图像处理后的结果 形态学图像处理 &#xff08;1&#xff09;腐蚀&#xff08;…

测试C#使用AForge从摄像头获取图片

百度“C# 摄像头”关键词&#xff0c;从搜索结果来看&#xff0c;使用OpenCV、AForge、window动态链接库获取摄像头数据的居多&#xff0c;本文学习基于Aforge.net连接摄像头并从摄像头获取图片的基本方法。   AForge相关包&#xff08;尤其是相关的控件&#xff09;主要针对…

【AIPRM】-高效管理Prompt模板,让你与众多AI互动更加流畅

关于AIPRM 链接: AIPERM AIPRM&#xff1a;Google 推出的AI提示管理工具。它提供多样化的Prompt模板&#xff0c;能帮助你与各种AI进行更加高效的互动。 登录 在主页点击“免费安装”–>Add to Chrome。 安装完成后&#xff0c;你在新的ChatGPT界面里面&#xff0c;能…

【四】记一次关于架构设计从0到1的讨论

记一次关于架构设计从0到1的讨论 简介&#xff1a; 在一次面试中和面试官讨论起来架构设计这个话题&#xff0c;一聊就不知不觉一个小时了&#xff0c;感觉意犹未尽。现在回想起来感觉挺有意思的&#xff0c;古人说独学而无友则孤陋而寡闻&#xff0c;的确是这样的&#xff0c…

基于SSM的搬家预约系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的搬家预约系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

css的定位

为什么需要定位&#xff1f; 场景&#xff1a; 某个元素可以自由的在一个盒子内移动位置&#xff0c;并且压住其他盒子当我们滚动窗口的时候&#xff0c;盒子是固定屏幕某个位置的。 这二个需求&#xff0c;使用标准流和浮动的方式是无法实现的或者是不容易实现&#xff0c;所以…

date-fns v3 发布——这个由 200 个函数组成的 JavaScript 日期处理套件

date-fns v3 发布——这个由 200 个函数组成的 JavaScript 日期处理套件已经在 TypeScript 中重写&#xff0c;重新引入了 String 日期参数&#xff0c;在 Node 上支持 ESM&#xff0c;并且所有函数现在都可以通过命名导出导出。 经过几个月的开发&#xff0c;v3 终于出来了&a…

手写Vue2源码

手写Vue2 使用rollup搭建开发环境 使用rollup打包第三方库会比webpack更轻量&#xff0c;速度更快 首先安装依赖 npm init -ynpm install rollup rollup-plugin-babel babel/core babel/preset-env --save-dev然后添加 rollup 的配置文件 rollup.config.js import babel f…

react 路由v6

这里是区别&#xff1a;V5 vs V6 这里是官网&#xff1a;可以查看更多高级属性 一、基本使用&#xff1a; 1、配置文件 src/routes/index import React from "react";const Home React.lazy(() > import("../Pages/Home")); const About React.laz…

探索 HTTP 请求的世界:get 和 post 的奥秘(上)

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

html之如何设置音频和视频

文章目录 前言一、音频标签&#xff1a;audio1.audio简介2.常用属性controlsautoplayloop代码演示&#xff1a; 二、视频标签&#xff1a;video1.video2.常用的视频元素controlsautoplayloop代码演示&#xff1a; 总结视频元素总结音频元素总结 前言 html中插入音频和视频的方…

超维空间S2无人机使用说明书——51、使用yolov8进行目标跟踪

引言&#xff1a;为了提高yolo识别的质量&#xff0c;提高了yolo的版本&#xff0c;改用yolov8进行物体识别&#xff0c;同时系统兼容了低版本的yolo&#xff0c;包括基于C的yolov3和yolov4&#xff0c;以及yolov7。 简介&#xff0c;为了提高识别速度&#xff0c;系统采用了G…

14章总结

一.lambda表达式 1.lambda表达式简介 lambda表达式不能独立执行&#xff0c;因此必须实现函数式接口&#xff0c;并且会返回一个函数式接口的对象。 语法&#xff1a; ()->结果表达式 参数->结果表达式 (参数1&#xff0c;参数2&#xff0c;...&#xff0c;参数n)->…

老鹰目标检测数据集VOC格式60张

老鹰是天空中的王者&#xff0c;它们拥有极佳的飞行能力。它们能以惊人的速度在天空中翱翔&#xff0c;尤其擅长高空俯冲捕食。老鹰的视力非常敏锐&#xff0c;能够准确地发现地面上的猎物&#xff0c;并迅速下落抓取。它们的爪子强而有力&#xff0c;足以击倒比自己体型庞大的…

顶级旗舰ET9出道,蔚来还是那个「最不计成本」的中国车品牌

作者 |张祥威 编辑 |德新 2008年&#xff0c;李斌和新浪的曹国伟几人一起喝酒&#xff0c;发了第一条微博&#xff0c;「天冷带围巾&#xff0c;心冷发微博」&#xff0c;一晚上涨了2000多个粉丝&#xff0c;他偶尔还会针砭时事&#xff0c;很快积累了最早一波粉丝。 创立蔚来…