【每日一题】7月3日精讲—毒瘤xor

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 32768K,其他语言65536K
Special Judge, 64bit IO Format: %lld

题目描述

输入描述:

第一行一个整数N,表示序列的长度 第二行N个整数,表示序列内的元素 第三行一个整数q,表示询问的个数 接下来q行,每行两个整数[L,
R],表示询问的区间

输出描述:

输出q行,每行一个整数表示答案

若有多组可行解,请输出较小的解

示例1
输入
复制

5 
4 78 12 1 3
3
2 5
1 4
3 3

输出

2147483632
2147483635
2147483635

备注:

对于30%的数据,n , q ≤ 10
对于60%的数据,n , q ≤ 1000
对于100%的数据,n, q ≤ 10^5
保证ai < 2^31

题解:

很久没有遇到异或的题了
先讲下异或:1 ^ 1 =0 , 0 ^ 0= 0,1 ^ 0 =1,0 ^ 1 =1
相同为0,不同为1
异或是两个数二进制状态下相同数位进行操作
我们要找一个x使得x ^ a[i]的和最大,那我们就尽量使x与a[i]的相同位数异或后为1,这样就最大
a[i]是一个数组,所以我们就求这个数组里每个数的二进制状态下,每一位0和1的个数,比如说,数组有n个数,其中b个数二进制状态下第一位是0,剩下n-b个数二进制状态下第一位是1,如果b>n-b,那我们就使X二进制的第一位是1,(就是和最多情况的数呈相反,这样异或出来才是1)
然后是第二位,依次类推最后我们就得到X的二进制状态,转化成十进制输出即可
因为有多轮询问,所以我们可以用前缀和来处理每一位为1的数

		bool w=((a[i]>>j)&1);//判断第j位是0是1 
		sum[i][j]=(sum[i-1][j]+w);//前缀和进行累加

代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+4;
typedef long long ll;
ll a[maxn];
int sum[maxn][40];
int main()
{
   
	int n;
	cin>>n;
	for(int i=1;i<=n;i++)
	{
   
		cin>>a[i];
	}
	for(int i=1;i<=n;i++)
	{
   
		for(int j=0;j<31;j++)
		{
   
			bool w=((a[i]>>j)&1);//判断第j位是0是1 
			sum[i][j]=(sum[i-1][j]+w);
		}
	}
	int q;
	cin>>q;
	int tot=0;
	while(q--)
	{
   
		tot=0;
		int l,r;
		cin>>l>>r;
		for(int j=0;j<31;j++)
		{
   
			if(sum[r][j]-sum[l-1][j] < ( (r-l)/2+1) )//当这一位0居多时,X选为1 
			tot+=(1<<j); 
		}
		cout<<tot<<endl; 
	}
}