首页 > 其他分享 >异或问题合集

异或问题合集

时间:2023-11-11 23:24:34浏览次数:32  
标签:log Trie 复杂度 times 问题 异或 oplus 合集

评价:我有异或症。

收集了一些跟异或相关的 trick,主要是以题目的形式放出来,做到了新的会再加。

由于本人不太会线性基,正在考虑要不要改成 01-Trie 学习笔记,相关题目暂时应该是没有,主要考虑异或本身的性质。

P4551 最长异或路径

题目链接

设 \(dis_u\) 表示根到 \(u\) 路径上所有边权的异或和,众所周知异或有个很好的性质就是 \(a\oplus a=0\),那么根据这点我们不难发现:\(u,v\) 路径上的边权异或和就等于 \(dis_u\oplus dis_v\),因为 LCA 向上的边权都异或两次消去了。

现在的问题就变成:找出最大的一个点对 \((u,v)\),使得 \(dis_u\oplus dis_v\) 最大。

将所有 \(dis_i\) 从高位到低位插入到 Trie 中,然后枚举 \(dis_u\),贪心地从 Trie 上向下走找到最大的 \(dis_u\oplus dis_v\) 即可。具体来说就是每次看看能不能朝相反的那一位走,因为是从高位到低位插入这样一定是最优的。这个是非常基础的,相信大家都会。

时间复杂度 \(O(n\log V)\)。

P9745 树上异或

题目链接

插播一个 dp 题。

朴素的想法是设 \(f_{u,i}\) 表示 \(u\) 所在的连通块权值为 \(i\) 时(只考虑子树内),子树内其他连通块的贡献之和,\(g_u\) 表示 \(u\) 所在子树的答案。

\(f_{u,i}\) 的转移就考虑每个儿子到自己的边断不断:

\[f_{u,i}\leftarrow f_{u,i}\times g_v+\sum_j f_{u,j}\times f_{v,i\oplus j} \]

\(g_u\) 其实就求个和:

\[g_u=\sum_{x}x\times f_{u,x} \]

时间复杂度 \(O(nV)\),肯定过不去。

异或的一个很好的性质就是运算过程中每一位之间都是独立的,不妨按位考虑,也就是拆位。

设 \(f_{u,i,0/1}\) 表示 \(u\) 所在连通块权值的第 \(i\) 位为 \(0/1\) 时(同样也只考虑子树内),子树内其他连通块的贡献之和,\(g_u\) 表示 \(u\) 所在子树的答案。

转移其实大差不差:

\[\begin{aligned} f_{u,i,0}&\leftarrow f_{u,i,0}\times g_v+f_{u,i,0}\times f_{v,i,0}+f_{u,i,1}\times f_{v,i,1} \\ f_{u,i,1}&\leftarrow f_{u,i,1}\times g_v+f_{u,i,0}\times f_{v,i,1}+f_{i,i,1}\times f_{v,i,0} \end{aligned} \]

哦,还有 \(g_u\) 改成这样:

\[g_{u}=\sum_{i}2^i\times f_{u,i,1} \]

时间复杂度 \(O(n\log V)\)。

P5283 异或粽子

题目链接

对 \(a_i\) 做一个异或前缀和,也就是记 \(s_i=\oplus_{j=1}^i a_i\),那么区间 \([l,r]\) 的异或和就可以转化为 \(s_r\oplus s_{l-1}\),特别规定 \(s_0=0\) 即可。

于是问题就转化成了:给你一个序列 \(s\),求前 \(k\) 大的两两异或值之和。

注意这里要求 \(s_i\oplus s_j\) 时有 \(i<j\),这是比较烦人的,但我们可以直接将 \(i<j\) 的限制去掉,转而求前 \(2k\) 大的两两异或值,然后再将答案除以 \(2\) 就好了,因为发现这样只是把 \(i,j\) 和 \(j,i\) 重复算了一遍(由于有 \(s_i\oplus s_i=0\),\(i=j\) 的情况不需要任何特殊处理)。

事实上强制带 \(i<j\) 的限制也可以写可持久化 Trie 来解决。

考虑给定其中一个 \(s_i\) 时,能不能求出来第 \(k\) 大的 \(s_i\oplus s_j\)。其实是简单的,Trie 树上每个点维护子树内有几个数,把 \(s_i\) 扔到 Trie 上去进行一个类似于线段树上二分的过程就好了,当一位填 \(1\) 后最小排名不会超过 \(k\) 时就贪心填 \(1\)。

然后类比一下超级钢琴的做法,开一个小根堆,对于每个 \(s_i\) 先将最小的 \(s_i\oplus s_j\) 扔进堆里,这样就能保证堆顶一定是当前能取的最小值。接下来每次取出堆顶后,假如这个堆顶对它的 \(s_i\) 来说是第 \(t\) 小的,那就用上面方法把第 \(t+1\) 小的扔进去,这样重复 \(2k\) 次之后我们就成功求出前 \(2k\) 大的两两异或值了。

于是就做完了,时间复杂度 \(O((n+k)\log V)\)。

CF241B Friends

题目链接

乍一看这不就是异或粽子吗?但是发现 \(k\) 非常大,而上面做法的复杂度是带个 \(k\) 的,过不去。

其实我们还有一个跟 \(k\) 无关的 \(O(n\log^2 V)\) 做法。

首先还是先把 \(k\) 乘上 \(2\),这些就不多说了。然后我们分为两部分去完成:求出第 \(k\) 大的异或值 \(kth\),求出大于等于 \(kth\) 的异或值之和。

对于第一部分,考虑二分答案 \(mid\),判断 \(kth\) 是否小于等于 \(mid\)。不难发现此时我们只需要求出有多少对 \((i,j)\) 满足 \(a_i\oplus a_j>=mid\) 就行了,可以直接把每个 \(a_i\) 扔到 Trie 树上,类似线段树二分的过程(或者你也可以理解成枚举 LCP),如果遇到 \(mid\) 某位是 \(0\),那么与 \(a_i\) 这位相反的那棵子树内的 \(a_j\) 就都是合法的,借此求出有多少个满足条件的 \(a_j\) 即可。这部分是两个 \(\log\) 的。

对于第二部分,考虑在 Trie 树上每个点 \(u\) 额外维护一个 \(f_{u,x}\) 表示经过 \(u\) 的 \(a_i\) 中有几个二进制下第 \(x\) 位是 \(1\),这样把 \(a_i\) 扔到 Trie 树上走的过程中,如果遇到 \(kth\) 某位是 \(0\),那么与 \(a_i\) 这位相反的那个子树内的数与 \(a_i\) 异或后就一定是大于 \(kth\) 的,相当于是求 \(a_i\) 异或其它经过这棵子树的 \(a_j\) 的和,贡献可以直接拆位算出来。

这样的话时空都是两个 \(\log\) 的,可以通过,但是空间其实可以去掉一个 \(\log\)。

考虑将 \(a_i\) 从小到大排序,有这么个性质:经过 Trie 上某个结点的 \(a_i\) 一定是一段连续的区间。

因此可以直接对原序列拆位做一个前缀和,需要统计某棵子树的贡献拆位时可以对应其在序列中的左右端点,差分计算贡献。

这样就是时间两个 \(\log\),空间单 \(\log\) 了。

ABC252Ex K-th beautiful Necklace

题目链接

很好的神仙题!技巧性很强的题,感觉就是各种 trick 的杂糅。

下文中令 \(m\) 为原题中的 \(c\)。发现这个 \(n\) 的范围是很神奇的,让人很容易去想暴力的可行性。当 \(m\) 确定时直接爆搜的上界显然是 \(O((\frac{n}{m})^m)\) 的,那么整体的上界具体到底是多少呢?事实上 \(m=3\) 时会取到 \(10^{11}\) 左右。

直接搜显然是爆炸了,但是注意到如果折半的话那搜一半的复杂度就会开个根号,只有 \(10^5\) 的级别(上界其实是 \(5\times 10^5\) 左右),这是完全可以接受的,因此可以贪心地将颜色划分为大小乘积比较接近的两组,折半地将两组的选法先搜出来。

假设第一组搜出来的所有选法权值扔到序列 \(a\) 中,第二组搜出来的所有选法权值扔到序列 \(b\) 中,那么现在问题就转化成了:给你两个序列 \(a\) 和 \(b\),求 \(a_i\oplus b_j\) 的第 \(k\) 大值。

一个直接的想法是二分答案 \(mid\),把每个 \(b_i\) 扔到 Trie 中,然后对于每个 \(a_i\) 计算有多少 \(b_j\) 满足 \(a_i\oplus b_j\ge mid\) 即可。分析下复杂度,我们令 \(T\) 表示搜一半的复杂度上界,那么时间复杂度为 \(O(T\log^2 V)\),算下来快到 \(10^9\),好的看来是似了。

考虑干掉二分的 \(\log\):方法是直接让所有的 \(a_i\) 同时在 Trie 上移动。具体地,从高到低枚举答案每一位,计算每个 \(a_i\) 在当前位的相反方向上的子树内的 \(b_j\) 个数并求和,如果大于 \(k\) 说明答案这一位为 \(1\),集体向该位相反方向移动即可,否则说明答案这一位为 \(0\),全部向当前位的同方向移动,并将 \(k\) 减去刚刚算的个数即可。

现在的时间复杂度就是 \(O(T\log V)\) 的了,真的赢了。

标签:log,Trie,复杂度,times,问题,异或,oplus,合集
From: https://www.cnblogs.com/los114514/p/17826552.html

相关文章

  • maven打包fat-jar注意的问题
    前言:maven打包fat-jar注意的问题,在使用maven工程的时候,打包jar的时候大多数都会需要把相关的jar依赖都一起打包到一起,这边记录下关于解压依赖和不解压依赖打包的两种方式以及嵌套jar包该如何解决的问题maven配置在使用maven打包jar包的时候,这边相关的配置都是在pom.xml中进行变......
  • 【题解 P8763】[蓝桥杯 2021 国 ABC] 异或变换
    同楼上dalao做法:#include<iostream>#include<algorithm>#include<cstdio>#include<cmath>#include<cstring>#include<string>#include<cstdlib>#include<bitset>usingnamespacestd;constintN=1e4+10......
  • J 开关问题
    J开关问题Description:有一排\(n\)个开关,初始时,均处于关闭状态,现在按\(i=1,2,...,n\)的顺序执行共\(n\)次操作:第\(i\)次操作时,翻转第\(i\)个、第\(2i\)个、...、第\(⌊n/i⌋×i\)个开关,即,把打开的关闭,把关闭的打开。问:最终处于关闭状态的开关有几个?Hint对于......
  • SpringSecurity successHandler方法使用自定义Handler登录成功,302问题
    一开始我自定义了成功和失败两个Handler,在进行调试的时候发现失败的没有问题,但是登录成功的话走的是某人的重定向而不是我自定义的protectedvoidconfigure(HttpSecurityhttp)throwsException{http.csrf().disable().headers().frameOptions().disable()......
  • 如何修复页脚的 CSS 属性无法正确显示的问题?
    修复页脚的CSS属性无法正确显示的问题需要进行以下步骤:检查CSS代码:检查页脚CSS代码中是否存在拼写错误、语法错误等问题。确保代码中的所有属性和值都正确书写。检查选择器:确认CSS中的选择器是否正确匹配到页脚元素。可以在浏览器开发者工具中检查元素的样式是否被正确应用......
  • 想入坑golang web,向大佬们请教些问题?
    当你准备入坑Go语言的Web开发时,以下是一些常见的问题,你可以向大佬们请教:如何设置和启动一个GoWeb服务器?Go语言有哪些常用的Web开发框架?它们之间有什么区别和优劣势?Go语言中的路由是如何实现的?如何处理不同的HTTP请求方法和URL参数?Go语言如何处理请求和响应,以及如何......
  • css中多行省略号不生效的问题?
    多行省略号不生效的问题可能是由于以下原因之一:1.高度限制:多行省略号需要给容器元素设置一个固定的高度,否则文本会自动撑开容器,不会出现省略号。在你的代码中,如果.item元素没有设置高度,多行省略号效果可能无法生效。2.浏览器兼容性:多行省略号的样式属性-webkit-line-clamp是......
  • 有关于时间转换问题
    有关于时间转换split函数s1='lcyisapig'foriins1.split():#['lcy','is','a','pig']print(i)s2='lcyisapig'foriins2.split(''):#['','lcy','......
  • 信任问题
    ·安全问题的本质是信任的问题 ·一切安全方案的基础,都是建立在信任关系上的。我们必须相信一些东西,必须有一些最基本的假设,安全方案才会得以成立 如果我们否定一切,且对一切都不信任,安全方案就会成为无源之水,无根之木,无法设计,也无法完成。 ·在现实生活中我们一般很少设......
  • 如何解决多线程下的共享对象问题?分布式系统又该如何应对?
    嗨,各位小米粉丝们!欢迎来到小米带你飞的微信公众号!今天我们要聊的话题可是程序员们都头疼的大问题哦——多线程情况下的对象共用问题,以及在分布式系统中的应对策略!小米要给大家详细解读一下,让你的技术面试不再被问倒!多线程中,如何解决对象共用问题?首先,我们得先了解多线程带来的挑战。......