Description
农民约翰在喂奶牛的时候被另一个问题卡住了。他的所有N(1 <= N <= 100,000)个奶牛在他面前排成一行(按序号1..N的顺序),按照它们的社会等级排序。奶牛#1有最高的社会等级,奶牛#N最低。每个奶牛同时被指定了一个不唯一的附加值,这个数在 的范围内。
帮助农民约翰找出应该从哪一头奶牛开始喂,使得从这头奶牛开始的一个连续的子序列上,奶牛的附加值的异或最大。
如果有多个这样的子序列,选择结尾的奶牛社会等级最高的。如果还不唯一,选择最短的。
Solution
还是01Trie的经典题目,取一个区间的异或值
令前缀异或和
显然有
于是我们把问题转化为在前缀异或和里找两个数字,使得他们异或最大即可。
注意res初始值要赋值为负数!!!我在这里wa了好几次0.0
Code
#include <bits/stdc++.h> using namespace std; typedef long long ll; const int N = 1e5 + 5; int a[N]; int trie[N * 50][2]; map<int, int> mp; int tot; void add(int x, int i) { int rt = 0; for(int i = 30; i >= 0; i--) { int cur = ((x >> i) & 1); if(!trie[rt][cur]) trie[rt][cur] = ++tot; rt = trie[rt][cur]; } mp[rt] = i; } pair<int, int> query(int x) { int ans(0), rt(0); int pos(0); for(int i = 30; i >= 0; i--) { int cur = ((x >> i) & 1); if(trie[rt][cur ^ 1]) { ans |= (1LL << i); rt = trie[rt][cur ^ 1]; } else { rt = trie[rt][cur]; } } pos = mp[rt]; return make_pair(ans, pos); } int main() { ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); int n; cin >> n; int res(-1); for(int i = 1; i <= n; i++) { cin >> a[i]; a[i] ^= a[i - 1]; } int pos = -1, l, r; add(0, 0); for(int i = 1; i <= n; i++) { auto ans = query(a[i]); if(res < ans.first) { res = ans.first; r = i; l = ans.second; } add(a[i], i); } cout << res << ' ' << l + 1 << ' ' << r << '\n'; return 0; }