时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 32768K,其他语言65536K Special Judge, 64bit IO Format: %lld
@[toc]
题目描述
输入描述:
第一行一个整数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; } }