題面
A B C D E 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
從這裡開始難度陡增。
(未完)