[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]);elseD[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();}}
}

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

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

相关文章

KubeSphere金丝雀发布流量分布调节不生效(将所有流量按比例分配给灰度发布版本)

如题 金丝雀发布按照流量比例访问不能生效 1、自制应用生成的路由添加注释: nginx.ingress.kubernetes.io/service-upstream:"true" 2、项目网关开启 3、完成 以上&#xff0c;祝好。

Tomcat远程调试

windows环境 写一个 startup-debug.bat&#xff0c;指定tomcat的根目录&#xff0c;端口自己定义 rem *******设置Tomcat目录*******-- set CATALINE_HOMED:\asd\A8-2\tomcat d: rem 8787为可用端口,为远程调试监听端口-- cd %CATALINE_HOME%/bin set JPDA_ADDRESS8787 set J…

Leetcode—445.两数相加II【中等】

2023每日刷题&#xff08;六十七&#xff09; Leetcode—445.两数相加II 实现代码 /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/struct ListNode* addTwoNumbers(struct ListNode* l1, struct ListNode* l2…

一个简单的 HTTP 请求和响应服务——httpbin

拉取镜像 docker pull kennethreitz/httpbin:latest 查看本地是否存在存在镜像 docker images | grep kennethreitz/httpbin:latest 创建 deployment&#xff0c;指定镜像 apiVersion: apps/v1 kind: Deployment metadata:labels:app: httpbinname: mm-httpbinnamespace: mm-…

Latex生成的PDF中加入书签/Navigation/导航

本文参考&#xff1a;【Latex学习】在生成pdf中加入书签/目录/提纲_latex 书签-CSDN博客 &#xff08;这篇文章写的真的太棒了&#xff01;非常推荐&#xff09; 题外话&#xff0c;我的碎碎念&#xff0c;这也是我如何提高搜索能力的办法&#xff1a;想在Latex生成的PDF中加入…

2023的AI工具集合,google和claude被禁用解决和edge的copilot

一、前言 AI工具集合 首先&#xff0c;OpenAI的ChatGPT以其深度学习模型和强大的语言处理能力引领了AI聊天机器人的潮流。自2022年11月30日上线以来&#xff0c;它创下了100万用户的注册记录&#xff0c;并被广泛应用于全球财富500强公司。为了实现盈利&#xff0c;OpenAI发布…

iOS 开发设计 App 上架符合要求的截图

1. 真机运行截屏 2. 可以在 Apple developer 官网 Design 下找到 iPhone 边框 https://developer.apple.com/design/resources/ 不用这个边框也行&#xff0c;可以参考已上架 App 的图片框 3. 使用 Procreate&#xff08;PhotoShop&#xff09;创建符合要求的画布大小 4. 导入…

springboot集成websocket全全全!!!

一、界面展示 二、前置了解 1.什么是websocket WebSocket是一种在单个TCP连接上进行全双工通信的持久化协议。 全双工协议就是客户端可以给我们服务器发数据 服务器也可以主动给客户端发数据。 2.为什么有了http协议 还要websocket 协议 http协议是一种无状态&#xff0c;非…

铭飞CMS cms/content/list接口存在SQL注入 附POC

@[toc] 铭飞CMS cms/content/list接口存在SQL注入 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用…

内存函数的学习

额外知识点 第一个 假设c为int类型&#xff0c;&#xff08;char&#xff09;c之后&#xff0c;之后如果还用变量c的话&#xff0c;c依然为int类型。&#xff08;&#xff09;强制转换操作符并不会永久改变原本的变量类型。 第二个 \0在打印时不会显示出来 第三个 void …

增强客户获取能力:探索 B 端影片行销的影响

01 B端企业短视频营销的价值与难点 短视频营销在当今的市场中越来越受到重视。有数据显示&#xff0c;越来越多的市场人将尝试增加短视频营销的预算&#xff0c;并且在2023年&#xff0c;每5个市场人中就有1个人将尝试短视频营销。相较于内容深、信息量大的长视频&#xff0c;…

串口通信(7)-C#串口通信通信帮助类实例

本文讲解C#串口通信通信帮助类实例 首先创建winform项目添加界面和控件 UI界面 namespace SerialPortDemo {partial class MainForm{/// <summary>/// 必需的设计器变量。/// </summary>private System.ComponentModel.IContainer components = null;/// <sum…

c#委托学习笔记1

委托三步骤 第一步&#xff1a;定义委托 //第一步&#xff1a;1 声明委托(定义委托) //对于声明委托的解释如下&#xff1a; //解释a&#xff1a;函数指针 //解释b&#xff1a;委托就是定义函数的形状&#xff08;形态&#xff09; // 即&#xff1a;返回值类型&#x…

宝塔面板 -- 创建第一个自己的网站

文章目录 前言 一、安装宝塔面板 二、注册宝塔面板 三、安装nginx 四、第一个hello world运行 五、总结 文章目录 前言一、安装宝塔面板二、注册宝塔面板三、安装nginx四、第一个hello world运行五、总结 前言 阿里云最近对在校大学生免费每人赠送一台服务器&#xff0c…

展望2023年CSDN博客之星评选

目录 1 前言2 博客的意义3 人工智能对博客的影响4 AI 技术下的成长与分享5 技术的探索6 博客之星评选对于技术人的激励作用7 结语 1 前言 当我们回顾过去&#xff0c;博客不仅仅是一种记录生活、分享经验的方式&#xff0c;更是一个见证自我成长与进步的平台。站在2023年度 CS…

uniapp实战 -- 个人信息维护(含选择图片 uni.chooseMedia,上传文件 uni.uploadFile,获取和更新表单数据)

效果预览 相关代码 页面–我的 src\pages\my\my.vue <!-- 个人资料 --><view class"profile" :style"{ paddingTop: safeAreaInsets!.top px }"><!-- 情况1&#xff1a;已登录 --><view class"overview" v-if"membe…

离散型制造企业为什么要注重MES管理系统的实施

离散型制造企业经常面临三个核心问题&#xff1a;生产什么、生产多少以及如何生产。尽管许多企业都实施了ERP系统&#xff0c;但仍然绕不开MES管理系统的话题。本文将从三个方面详细解释为什么离散型企业需要实施MES管理系统。 一、生产线经常出现的问题 在离散型企业中&#…

Leetcode 45 跳跃游戏 II

题意理解&#xff1a; 给定一个长度为 n 的 0 索引整数数组 nums。初始位置为 nums[0]。 每个元素 nums[i] 表示从索引 i 向前跳转的最大长度。 还是从初始坐标i0的位置到达最后一个元素&#xff0c;但是问题不是能不能跳到&#xff0c;而是最少几步能跳到最后一个元素。 目标&…

Javascript:DOM对象

Javascript&#xff1a;DOM-获取对象 DOM与JavaScript的关系什么是DOMDOM相关概念DOM 树DOM 节点DOM对象 获取DOM对象通过CSS选择器来获取DOM对象其他方式 操作DOM对象控制DOM对象内容控制DOM对象属性控制HTML标签属性控制CSS样式通过style属性操作CSS通过类名(className) 操作…

详解KMP算法

KMP算法应该是每一本《数据结构》书都会讲的&#xff0c;算是知名度最高的算法之一了&#xff0c;但很可惜&#xff0c;我大二那年压根就没看懂过~~~ 之后也在很多地方也都经常看到讲解KMP算法的文章&#xff0c;看久了好像也知道是怎么一回事&#xff0c;但总感觉有些地方自己…