洛谷题单指南-字符串-P4735 最大异或和

news/2024/10/21 12:38:33

原题链接:https://www.luogu.com.cn/problem/P4735

题意解读:已知长度为n的数组a[],要在l~r范围找到一个p,使得a[p]^a[p+1]^...^a[n]^x最大,求这个最大的异或值。

解题思路:

1、利用前缀和将问题转化

设s[]是a[]的前缀异或数组,要计算a中一段范围l~r的异或,可以借助于s

由于s[r] = a[0]^a[1]^...a[l-1]^a[l]^...^a[r],s[l-1] = a[0]^a[1]^...^a[l-1]

因此s[r] ^ s[l-1] = a[l]^a[l+1]^...^a[r]

对于a[p]^a[p+1]^...^a[n]^x,可以转化为s[n]^x^s[p-1],即问题转化为在s[l-1]~s[r-1]范围内找到一个s[p-1]使得s[n]^x与其异或值最大。

要计算与一个数异或最大的值,可以借助于Trie树,但是这里限制条件是要在一个范围内找到与某个数异或的最大值,需要引入一种新的数据结构-持久化Trie树。

2、持久化Trie树介绍

所谓持久化Trie,一般用于01Trie,是指对每一个数字进行加入trie操作时,都建立一个新的根节点,从该根节点可以查找到之前添加的所有的数,具体如何实现呢?我们以2 6 4 3 为例进行Trie添加操作:

添加的过程有以下特点:

  • 每添加一个数s[i],都建立一个根节点root[i],从root[i]可以查找到s[1]~s[i]所有数
  • 当添加s[i]时,对于s[i]的每一个二进制位都新建立节点,对于不在s[i]中的二进制位,复制前一个根的节点
  • 如添加6时,trie[6][0]=trie[1][0]是复制前一个根节点,而trie[6][1]=7是新建节点

查找的过程:

要在L~R范围内查找与x异或最大的结果,可以在根为root[R]中去找1~R范围的数,同时用一个maxid[]来记录Trie树中每一个节点所经过的数的最大id,这样在查找最大异或值时,只需要判断相反位节点存在且maxid[]>=L即说明是L~R范围的数,不存在则走相同位的节点。

Trie树操作核心代码:

//将s[id]添加到持久化Trie
void add(int id)
{root[id] = ++idx; //创建当前根节点int cur = root[id]; //当前根int pre = root[id - 1]; //前一个根for(int i = 23; i >= 0; i--){int v = s[id] >> i & 1;trie[cur][!v] = trie[pre][!v]; //相反位复制上一个根trie[cur][v] = ++idx; //对s[i]每个二进制位新建节点maxid[cur] = id; //更新maxidcur = trie[cur][v], pre = trie[pre][v]; //根沿着s[i]的二进制位往下走}maxid[cur] = id; //更新maxid
}//在l~r范围内查找与val异或的最大值
int find(int l, int r, int val)
{int res = 0;int u = root[r]; //根for(int i = 23; i >= 0; i--){int v = val >> i & 1;if(maxid[trie[u][!v]] >= l) //如果相反位的节点存在且最大编号>=l{u = trie[u][!v];res = res * 2 + 1; //异或后1对结果的贡献}else{u = trie[u][v];res = res * 2; //异或后0对结果的贡献}}return res;
}

3、最终问题求解

第一步:计算前缀异或

第二步:建立持久化Trie

第三步:范围查找最大异或值

100分代码:

#include <bits/stdc++.h>
using namespace std;const int N = 600005, M = N * 24;
int s[N]; //前缀异或数组
int root[N]; //所有版本trie的根节点
int trie[M][2], idx, maxid[M]; //trie树,maxid[]保存经过某个节点的数的最大s编号
int n, m;
char op;
int l, r, x;//将s[id]添加到持久化Trie
void add(int id)
{root[id] = ++idx; //创建当前根节点int cur = root[id]; //当前根int pre = root[id - 1]; //前一个根for(int i = 23; i >= 0; i--){int v = s[id] >> i & 1;trie[cur][!v] = trie[pre][!v]; //相反位复制上一个根trie[cur][v] = ++idx; //对s[i]每个二进制位新建节点maxid[cur] = id; //更新maxidcur = trie[cur][v], pre = trie[pre][v]; //根沿着s[i]的二进制位往下走}maxid[cur] = id; //更新maxid
}//在l~r范围内查找与val异或的最大值
int find(int l, int r, int val)
{int res = 0;int u = root[r]; //根for(int i = 23; i >= 0; i--){int v = val >> i & 1;if(maxid[trie[u][!v]] >= l) //如果相反位的节点存在且最大编号>=l{u = trie[u][!v];res = res * 2 + 1; //异或后1对结果的贡献}else{u = trie[u][v];res = res * 2; //异或后0对结果的贡献}}return res;
}int main()
{cin >> n >> m;maxid[0] = -1; //不存在的节点maxid=-1,便于find中比较add(0); //第一个数添加0,使得便于区间计算for(int i = 1; i <= n; i++){cin >> s[i];s[i] = s[i - 1] ^ s[i]; //计算前缀异或add(i); //添加到持久化Trie} while(m--){cin >> op;if(op == 'A'){cin >> x;s[n + 1] = s[n] ^ x;n++;add(n);}else{cin >> l >> r >> x;cout << find(l - 1, r - 1, x ^ s[n]) << endl;}}
}

 

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

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

相关文章

go中,iota要放在const的最前面来声明

如图所示,1必须在2的前面声明,iota在const()里要最先声明,否则iota异常

PHP cli模式和fpm模式有什么区别

PHP的CLI模式与FPM模式主要的区别包括:它们的运行环境不同、使用场景不同、性能表现不同、配置方式不同。 在深入了解两者之间的区别之前,我们首先必须了解CLI(命令行界面)和FPM(FastCGI进程管理器)的基本概念。CLI模式是专门为命令行脚本执行设计的,并在不与Web服务器集…

为什么说Kafka还不是完美的实时数据通道

本文主要谈谈Kafka用于实时数据通道场景的缺陷,以及如何在架构上进行弥补。 Kafka归属于消息队列类产品,其他竞品还有RabbitMQ、RocketMQ等,总的来说它们都是基于生产者、中介和消费者三种角色,提供高并发、大数据量场景下的消息传递。Kafka诞生自Hadoop生态,与生态中的其…

如何在C语言中使用外部库

在C语言中使用外部库,首先,你需要找到你需要的库,这可以在网上或者在本地机器上,并获取库的路径。其次,你需要用预处理指令#include <库名.h>将库包含到你的程序中。最后,你需要在链接阶段,用-l库名将库链接到你的程序中。使用外部库可以方便地使用库中预定义的函…

CTF学习( 3):Misc(二维码)

1.见到二维码图片,查看详细信息是否藏有flag(无果),使用QR Research查看二维码中是否藏有隐藏信息 (发现) 2.使用010 editor打开后文本搜索flag,key等关键字无果->发现在文件尾藏了数据(笔记:PNG文件由文件头"89 50 4E 47"和数据块"chuk"组成,50 4B 03 …

modsecurity: 规则的体系一

一,每个事务的生命周期: 如图:每个事务在modsecurity需要经历5个阶段,在每个阶段可能需要解析等操作,然后调用相应阶段的规则进行匹配,对应规则中的phase 阶段一:request headers请求头,这是modsecurity最先接触到的数据, 需要验证请求头相关的规则,并根据请…

SpringBoot 使用WebSocket

WebSocket 是一种网络通信协议,提供了在单个TCP连接上进行全双工通信的能力。这意味着客户端和服务器可以同时发送和接收数据,而不需要等待对方的回应。 Spring Boot 提供了对WebSocket的自动配置和简化的编程模型,使得在Spring Boot应用程序中集成WebSocket变得相对简单。 …

Leetcode 1584. 连接所有点的最小费用

1.题目基本信息 1.1.题目描述 给你一个points 数组,表示 2D 平面上的一些点,其中 points[i] = [x_i, y_i] 。 连接点 [x_i, y_i] 和点 [x_j, y_j] 的费用为它们之间的 曼哈顿距离 :|x_i – x_j| + |y_i – y_j| ,其中 |val| 表示 val 的绝对值。 请你返回将所有点连接的最小…