トピック
入力サンプル
5
1
0
5
4
2
サンプル出力
6 4 5
回答
- 最大間隔の排他的論理和を見つけることは01辞書ツリーの変形です。ここでのボードポイントは、2つの数値の最大の排他的論理和を見つけることです。この質問は、区間の排他的論理和の合計を見つけることです。その後、プレフィックス合計を使用できます。やろうと思う
- s配列を使用して、前のi番号の排他的論理和s [l-1] ^ s [r] = al ^ al + 1 ^ al + 2 ^…^ arを表すと、任意の排他的論理和を見つけることができます。連続間隔アップ
- 条件は、間隔の最大XORを満たし、rをできるだけ小さくすることです。次に、左から右にトラバースし、右の端点が1ビット増加するたびに(つまり、間隔の長さ+ 1)、を参照してください。この間隔での最大XOR量、それがより大きい場合は回答を更新します(rができるだけ小さいことを確認する必要があるため、更新しないことに等しい)
- もう1つの条件は、代替シーケンスがまだ複数ある場合は、長さが最も短いものが選択されることです。意味は、lをできるだけ大きくすることです。挿入するときに、前に同じ値を後者の値で上書きするだけでよいため、各出力は後者の値でなければなりません。
- まだ理解していませんか?たとえば、s [3] = 5、s [5] = 5、s [7] = 9とすると、最初の2つの条件が満たされているとすると、問題の要件はs [7] ^ s [5]でなければなりません。 、次に、s [3]を回避するにはどうすればよいですか。つまり、挿入するときに、各ポイントの添え字を記録します。番号5の場合、辞書ツリーへの挿入数は、前から後ろの順に2倍にする必要があります。最初に5を1回挿入し、添え字を3として記録し、2回目に5を挿入して、それがすでに存在することを確認します。新しいノードを開く必要はありません。ノード5の添え字を5に変更するだけです。
コード
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e5 + 10;
const int M = N * 21;
int n, x;
int s[N], id[M];
int tr[M][2], idx;
void insert(int x, int k) {
int p = 0;
for (int i = 20; i >= 0; i--) {
int u = x >> i & 1;
if (!tr[p][u]) tr[p][u] = ++idx;
p = tr[p][u];
}
id[p] = k; //记录下标,覆盖操作
}
int query(int x) {
int p = 0;
for (int i = 20; i >= 0; i--) {
int u = x >> i & 1;
if (tr[p][u ^ 1]) p = tr[p][u ^ 1];
else p = tr[p][u];
}
return id[p];
}
int main() {
cin >> n;
insert(s[0], 0);
int res = -1;
int l, r;
for (int i = 1; i <= n; i++) {
cin >> x;
s[i] = s[i - 1] ^ x;
int k = query(s[i]);
int maxn = s[i] ^s[k];
if (maxn > res) {
res = maxn;
l = k + 1, r = i;
}
insert(s[i], i);
}
cout << res << " " << l << " " << r << endl;
return 0;
}