NC18979 毒瘤xor
题目
题目描述
小a有 \(N\) 个数 \(a_1, a_2, ..., a_N\) ,给出 \(q\) 个询问,每次询问给出区间 \([L, R]\) ,现在请你找到一个数 \(X\) ,使得
- \(0 \leq X < 2^{31}\)
- \(\sum_{i = L}^R X \oplus a[i]\) 最大,\(\oplus\) 表示异或操作(不懂的请自行百度)
输入描述
第一行一个整数 \(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\)
保证 \(a_i < 2^{31}\)
题解
知识点:贪心,位运算。
显然不能每次枚举,需要更快的贪心方法构造一个 \(X\) 。
对于位运算的贪心,只需要让每位到达最优就行,因为互相独立。因此,本题只要对于 \(X\) 的每一位产生的和最大即可。
考察所有 \(a_i\) 某一位,要让这位异或和最大,就要考虑这位的 \(1\) 和 \(0\) 的数量,如果 \(1\) 多,则 \(X\) 这位应为 \(0\) ,否则为 \(1\) 。这里可以用二维数组 \(sum[i][j]\) 代表 \([1,i]\) 的数字中第 \(j\) 位是 \(1\) 的数量,前缀和预处理即可。
但要注意的是,我们要求最小的 \(X\) ,因此在两者皆可时 \(0\) 更优,即 \(1\) 的数量为严格小于一半时就用 \(1\)。这里不能用 sum[r][i] - sum[l - 1][i] < (r - l + 1)/2 ,因为这是取下整,要取上整。
时间复杂度 \(O(n+q)\)
空间复杂度 \(O(n)\)
代码
#include <bits/stdc++.h>
using namespace std;
int a[100007], sum[100007][31];
int main() {
std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
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++) {
if (a[i] & (1 << j)) sum[i][j]++;
sum[i][j] += sum[i - 1][j];
}
}
int q;
cin >> q;
while (q--) {
long long l, r;
cin >> l >> r;
int x = 0;
for (int i = 0;i < 31;i++) {
if (2 * (sum[r][i] - sum[l - 1][i]) < r - l + 1) x |= (1 << i);///这里要除的话取上整
}
cout << x << '\n';
}
return 0;
}
本文来自博客园,作者:空白菌,转载请注明原文链接:https://www.cnblogs.com/BlankYang/p/16384066.html

浙公网安备 33010602011771号