问题的根源是有个同学问了个lucky number的问题Codeforces 280B, Codeforces 281D也是同样的问题。
Find all unique pairs of maximum and second maximum elements over all sub-arrays in O(NlogN)
幸运数的定义为:数组中子数组的最大值和次大值的XOR值。寻找所有幸运数中的最大的。
Brute force 的解法是枚举所有的子数组,时间复杂度为O(N ^ 2).
有没有更优的方法呢?
今天要讨论的就是这个问题。
通用的解法,快速寻找 最大次大值对 算法
寻找子数组中最大值和次大值其实是有快速算法的:
Find all unique pairs of maximum and second maximum elements over all sub-arrays in O(NlogN)
基于这个的观察:数组中的每个数,如果想要成为次大值,就只能和向前的第一个比他大的数 或 向后的第一个比他大的数组成。
我们可以维护一个 单调递减栈,加入新数时,维持单调递增需要弹出所有小于它的数,这时新数就是被弹出来的数后面的第一个比他大的数;栈顶中最大的数 就是 新数 向前的第一个比他大的数。
时间复杂度: O(N),
空间复杂度: O(N).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35
| #include <iostream> #include <stack> #include <vector>
using namespace std; using ll = long long;
int solve() { ll N; cin >> N; vector<ll> nums(N); for (ll i = 0; i < N; ++i) { cin >> nums[i]; } stack<ll> st; st.push(nums[0]); ll ans = 0; for (ll i = 1; i < N; ++i) { while (!st.empty() && nums[i] > st.top()) { ans = max(ans, nums[i] ^ st.top()); st.pop(); } if (!st.empty()) { ans = max(ans, nums[i] ^ st.top()); } st.push(nums[i]); } return ans; }
int main() { ll ans = solve(); cout << ans << endl; return 0; }
|
我独立思考出的解法
我的解法利用了XOR的性质,如果换成别的运算就不通用了。
首先遍历一遍找到最高的位数。
再遍历一遍找到最高的位数为1的那些数,我们先称其为 最高数。
从这些最高数出发,往两边扩充,直到遇到另一个最高数,在这个过程中寻找次大数并更新幸运数的最大值。可以证明,每个数最多被找2次。
所以,总的时间复杂度是 O(N), 空间复杂度 O(N).
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| #include <iostream> #include <vector>
using namespace std; using ll = long long;
int solve() { int N; cin >> N; vector<ll> nums(N); for (ll i = 0; i < N; ++i) { cin >> nums[i]; } const int MAX_BIT_BEGIN = 40; vector<vector<ll>> flag(MAX_BIT_BEGIN + 1, vector<ll>(2, 0)); for (ll i : nums) { for (ll j = 0; j <= MAX_BIT_BEGIN; ++j) { ++flag[j][((i >> j) & 1)]; } } ll max_bit = MAX_BIT_BEGIN; for (; max_bit >= 0; --max_bit) { if (flag[max_bit][0] > 0 && flag[max_bit][1] > 0) { break; } } if (max_bit == 0) { return 1; } else if (max_bit < 0) { return 0; } else { vector<ll> max_bit_is_1_indexs; for (ll i = 0; i < N; ++i) { if (((nums[i] >> max_bit) & 1) == 1) { max_bit_is_1_indexs.push_back(i); } } ll ans = 0; for (ll index : max_bit_is_1_indexs) { ll second_max = 0; for (ll i = index - 1; i >= 0 && ((nums[i] >> max_bit) & 1) == 0; --i) { second_max = max(second_max, nums[i]); ans = max(ans, nums[index] ^ second_max); } second_max = 0; for (ll i = index + 1; i < N && ((nums[i] >> max_bit) & 1) == 0; ++i) { second_max = max(second_max, nums[i]); ans = max(ans, nums[index] ^ second_max); } } return ans; } }
int main() { ll ans = solve(); cout << ans << endl; return 0; }
|