Codeforces 1847 A-F
题面
题解
B
题目大意:找到一组分割方法,使得 \(\sum _{i=1} ^ k (\text{&} _{j=l_i} ^ {r_i} a_j)\) 取得最小值时使 \(k\) 最大,输出 \(k\)。其中 \(\text{&}\) 表示按位与操作。
题目分析:
| & | 0 | 1 |
|---|---|---|
| 0 | 0 | 0 |
| 1 | 0 | 1 |
不难发现,因为 \(a \in \mathbb{N}\),所以 $$a, b \ge a \& b \tag{1}$$ $$a + b \ge a \& b \tag{2}$$且对于公式 (2),当且仅当 \(a=b=0\) 时取等。
因此考虑贪心。设 \(x = \text{&} _{i=1} ^ {n} a_i\)。对于 \(x > 0\) 的 情况,根据 (2),分成一组的和是最优的,因此 \(k = 1\);对于 \(x = 0\) 的情况,只要将原数组分为几段区间按位与都为 \(0\) 的区间即可。
代码略。
C
题目大意:对于数组 \(a\),它的前 \(n\) 个数由题目给定,而 \(a_i(i > n) = \oplus _{j=k} ^ {i-1} a_j\),其中 \(k\) 不确定,\(1 \le k \le i - 1\),而 \(\oplus\) 表示按位异或。求 \(a\) 中元素的最大可能值。
这套题怎么这么多位运算?
题目分析:
| \(\oplus\) | 0 | 1 |
|---|---|---|
| 0 | 0 | 1 |
| 1 | 1 | 0 |
题目给定 \(a_i < 2^8 (1\le i\le n)\),所以由按位与的定义得到全体 \(a_i < 2^8\)。
设 \(a_p = \oplus _{i=l} ^{p-1} a_i\),则 \(a_{p+1}=\oplus _{i=k} ^{p} a_i=(\oplus _{i=k} ^{p-1} a_i) \oplus a_p = (\oplus _{i=k} ^{p-1} a_i) \oplus (\oplus _{i=l} ^{p-1} a_i) = \oplus _{i=min(k, l)} ^{max(k, l)-1} a_i\)。
于是问题转化为求最大字段异或。又因为异或运算满足结合律,可以用前缀异或加速。
问题再次转化为:求前缀异或数组中,任意两数异或的最大值。
由于 \(a_i < 2^8\),所以前缀异或数组中元素的值也在这个值域内。因此考虑用桶记录前缀数组中的数,然后与前缀数组进行“配对”求异或值。时间复杂度 \(O(2^8 \times n)\),可以通过这道题。
#include <bits/stdc++.h>
using namespace std;
int t, n, a[100010];
bool x[100010];
int main() {
scanf("%d", &t);
while (t--) {
memset(x, 0, sizeof(x));
scanf("%d", &n);
int ans = 0;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
a[i] ^= a[i - 1];
x[a[i]] = 1;
ans = max(ans, a[i]);
}
for (int i = 1; i <= n; i++) {
for (int j = 0; j < 256; j++) {
if (x[j]) {
ans = max(ans, a[i] ^ j);
}
}
}
printf("%d\n", ans);
}
return 0;
}
D
从这里开始难度陡增。
(未完)
本文来自博客园,作者:cwkapn,转载请注明原文链接:https://www.cnblogs.com/cwkapn/p/18529186


浙公网安备 33010602011771号