选数异或 (AcWing 4645)

2024-03-20 11:04
文章标签 acwing 异或 选数 4645

本文主要是介绍选数异或 (AcWing 4645),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

题目链接: https://www.acwing.com/problem/content/description/4648/

题目描述:

评价: 这道题感觉还是蛮有意思的,难度适中,而且有一定的思维含量,值得反复品味。

思路: 首先我们定义一个数组g[N], 其中的每个元素g[i] 表示在所有 i<j<=n 的j中,满足a[j] ^ a[i] = x的最小的那个j.  这是因为如果存在多个这样的j, 最小的那个j一定是最优的,因为他更加容易被包含在一个区间[l,r] 中. 

假设我们已经得到了上面的数组g, 那么实际上题目的问题就转化为: 每次给定一个查询[l,r] ,询问所有 l=< i <=r 的 i 是否存在一个g[i] <= r. 进一步,我们将这个问题转化为:

询问数组g在区间[l,r] 上的最小值是否小于等于r. 这是一个区间查询问题,且这个问题是满足区间可加性的,可以用线段树解决。

那么只需要考虑数组g 是如何构建的,注意到,若给定a, 满足 a^b=c 的b的取值是唯一的(等式两边异或上a就不难证明),因此,对于每一个位置i,满足t ^ a[i] =x 的值t是唯一的,我们只需要知道数组中数值 t 出现的全部位置即可; 另一方面,由于数组g的定义,因此需要动态维护每个数值出现的索引(要保证后面的位置不能够使用前面的位置的信息),因此可以用一个队列(先进先出)来进行维护。

参考代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<unordered_map>
#define ll long long
using namespace std;
const int N=1e5+10;
const int inf=1e9+7;
int n,m,x;
int a[N];
int g[N];
unordered_map<int,int> hashs;
queue<int> q[N];
int cnt=0;struct node{int l;int r;int minnum;
};
node tree[4*N];
void push_up(int cur){tree[cur].minnum=min(tree[cur<<1].minnum,tree[cur<<1|1].minnum);return ;
}
void build(int cur,int l,int r){tree[cur].l=l;tree[cur].r=r;if(l==r) {tree[cur].minnum=g[l];return ;}int mid=l+r>>1;build(cur<<1,l,mid);build(cur<<1|1,mid+1,r);push_up(cur);return ;
}int gets(int cur,int l,int r){if(tree[cur].l>=l&&tree[cur].r<=r){return tree[cur].minnum;}int mid=tree[cur].l+tree[cur].r>>1;int res1=inf;int res2=inf;if(l<=mid) res1=gets(cur<<1,l,r);if(r>=mid+1) res2=gets(cur<<1|1,l,r);int res=min(res1,res2);return res;
}int main(void){scanf("%d%d%d",&n,&m,&x);for(int i=1;i<=n;i++){scanf("%d",&a[i]);if(hashs[a[i]]==0){hashs[a[i]]=++cnt;}q[hashs[a[i]]].push(i);}for(int i=1;i<=n;i++){int tmp=x^a[i];q[hashs[a[i]]].pop();if(hashs[tmp]==0) g[i]=n+1;else{if(q[hashs[tmp]].empty()) g[i]=n+1;else g[i]=q[hashs[tmp]].front();}}build(1,1,n);for(int i=1;i<=m;i++){int l,r;scanf("%d%d",&l,&r);int res=gets(1,l,r);if(res<=r) printf("yes\n");else printf("no\n");}return 0;
}

这篇关于选数异或 (AcWing 4645)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/829262

相关文章

【AcWing】851. 求最短路

spfa算法其实是对贝尔曼福特算法做一个优化。 贝尔曼福特算法会遍历所有边来更新,但是每一次迭代的话我不一定每条边都会更新,SPFA是对这个做优化。 如果说dist[b]在当前这次迭代想变小的话,那么一定是dist[a]变小了,只有a变小了,a的后继(b)才会变小。 用宽搜来做优化,用一个队列,队列里边存的就是所有变小了的结点(队列里存的是待更新的点)。 基本思路就是我更新过谁,我再拿

【AcWing】852. spfa判断负环

#include<iostream>#include<algorithm>#include<cstring>#include<queue>using namespace std;const int N= 1e5+10;int n,m;int h[N],w[N],e[N],ne[N],idx;int dist[N],cnt[N];//cnt存最短路径的边数bool st[N];v

【OpenCV2.2】图像的算术与位运算(图像的加法运算、图像的减法运算、图像的融合)、OpenCV的位运算(非操作、与运算、或和异或)

1 图像的算术运算 1.1 图像的加法运算 1.2 图像的减法运算 1.3 图像的融合 2 OpenCV的位运算 2.1 非操作 2.2 与运算 2.3 或和异或 1 图像的算术运算 1.1 图像的加法运算 add opencv使用add来执行图像的加法运算 图片就是矩阵, 图片的加法运算就是矩阵的加法运算, 这就要求加法运算的两张图shape必须是相同的. # 图片加法imp

用异或交换两个整数的陷阱

前面我们谈到了,可用通过异或运算交换两个数,而不需要任何的中间变量。 如下面: void exchange(int &a, int &b) {     a ^= b;     b ^= a;     a ^= b; } 然而,这里面却存在着一个非常隐蔽的陷阱。 通常我们在对数组进行操作的时候,会交换数组中的两个元素,如exchang(&a[i], &b[j]),

异或运算的高级应用和Briankernighan算法

本篇文章主要回顾一下计算机的位运算,处理一些位运算的巧妙操作。 特别提醒:实现位运算要注意溢出和符号扩展等问题。 先看一个好玩的问题: $Problem1 $ 黑白球概率问题 袋子里一共a个白球,b个黑球,每次从袋子里拿2个球,每个球每次被拿出的机会均等。如果拿出的是2个白球、或者2个黑球,那么就往袋子里重新放入1个白球,如果拿出的是1个白球和1个黑球,那么就往袋子里重新放入1个黑球,那么

位运算 - 异或求和

异或求和 Problem's Link:  http://acm.xmu.edu.cn/JudgeOnline/problem.php?id=1254   Mean:  Description给你2个区间[A,B]和[C,D],现在只要求你求出区间[A,B]和[C,D]内任意2个整数异或后的和,因为答案可能会很大,你只需将结果%mod即可。For(i:A→B)For(j:

AcWing 282. 石子合并

必看的视频讲解↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 【E28【模板】区间DP 石子合并——信息学竞赛算法】 合并过程总开销等于红色数字总和,可以理解为花费的总体力! f数组的含义是f【i】【j】是从第i堆石子开始到第j堆石子的花费体力最小值 如何理解三层for呢? 第一层for是控制区间长度len,第二层for是控制区间起点位置i,第三层for是控制区间

AcWing 897. 最长公共子序列

动态规划就是多见识应用题就完事儿了,也没有什么好说的。 讲解参考: 【E05 线性DP 最长公共子序列】 #include<iostream>#include<algorithm>#define N 1010using namespace std;char a[N],b[N];int n,m;int f[N][N];int main(){cin >> n >> m >> a

AcWing 2. 01背包问题

一定要看的视频讲解:↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 【E08【模板】背包DP 01背包——信息学竞赛算法】 i表示放入i个物品,j表示第j个物品,用于访问体积v【j】 #include <iostream>#include <algorithm>using namespace std;const int N = 1010;int n, m;int v[N]

【数据结构-前缀异或和】力扣1371. 每个元音包含偶数次的最长子字符串

给你一个字符串 s ,请你返回满足以下条件的最长子字符串的长度:每个元音字母,即 ‘a’,‘e’,‘i’,‘o’,‘u’ ,在子字符串中都恰好出现了偶数次。 示例 1: 输入:s = “eleetminicoworoep” 输出:13 解释:最长子字符串是 “leetminicowor” ,它包含 e,i,o 各 2 个,以及 0 个 a,u 。 示例 2: 输入:s = “leetcodei