Maximum Xor Secondary
Bike loves looking for the second maximum element in the sequence. The second maximum element in the sequence of distinct numbers x1, x2, ..., xk (k > 1) is such maximum element xj, that the following inequality holds: .The lucky number of the sequence of distinct positive integers x1, x2, ..., xk (k > 1)is the number that is equal to the bitwise excluding OR of the maximum element of the sequence and the second maximum element of the sequence.
You've got a sequence of distinct positive integers s1, s2, ..., sn (n > 1). Let's denote sequence sl, sl + 1, ..., sr as s[l..r] (1 ≤ l < r ≤ n). Your task is to find the maximum number among all lucky numbers of sequences s[l..r].
Note that as all numbers in sequence s are distinct, all the given definitions make sence.
Input
The first line contains integer n (1 < n ≤ 105). The second line contains n distinct integers s1, s2, ..., sn (1 ≤ si ≤ 109).
Output
Print a single integer — the maximum lucky number among all lucky numbers of sequences s[l..r].
Examples
5
5 2 1 4 3
7
5
9 8 3 5 7
15
Note
For the first sample you can choose s[4..5] = {4, 3} and its lucky number is (4 xor 3) = 7. You can also choose s[1..2].
For the second sample you must choose s[2..5] = {8, 3, 5, 7}.
题意:给你一串数,问你这一串数的任意子串中的最大值和次大值的异或最大值为多少。
题解:
因为一个数可以是很多个区间的最大值,一个数也可以是很多个区间的次大值,所以我们可以以数为研究对象而非一个个区间。
第一种做法:
从前往后和从后往前各跑一遍单调栈,每次求的是以当前值为次大值,之前一个比它大的值为最大值,然后这两个值异或。因为单调栈求的就是这个数向左或者向右找第一个比它大的值的位置。所以这个数的位置和栈顶元素的位置构成的区间中,这个数和栈顶元素就是该区间里的次大值和最大值。
附代码:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<stack>
using namespace std;
const int maxn=1e5+10;
int ans;
stack<int>s;
stack<int>s2;
int a[maxn];
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
for(int i=0;i<n;i++)
{
while(!s.empty()&&a[s.top()]<a[i])
{
s.pop();
}
if(!s.empty())
ans=max(ans,a[i]^a[s.top()]);
s.push(i);
}
for(int i=n-1;i>=0;i--)
{
while(!s2.empty()&&a[s2.top()]<a[i])
{
s2.pop();
}
if(!s2.empty())
{
ans=max(ans,a[i]^a[s2.top()]);
}
s2.push(i);
}
printf("%d
",ans);
return 0;
}
第二种做法:
%大佬,思路差不多,只是只用求一遍单调栈就可以。从后往前求一遍单调栈然后记录一下对于每一个值它右边第一个比它大的值的位置。然后遍历一遍,每次可以同时求出该数作为最大值和次大值的异或值。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<stack>
#include<algorithm>
using namespace std;
const int maxn=1e5+10;
stack<int> s;
int r[maxn];
int a[maxn];
int main()
{
int n,ans;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
for(int i=n-1;i>=0;i--)
{
while(!s.empty()&&a[s.top()]<a[i])//找每个数右边第一个比它大的数的下标
{
s.pop();
}
if(s.empty())
{
r[i]=n;
}
else
{
r[i]=s.top();
}
s.push(i);
}
ans=0;
int t;
for(int i=0;i<n;i++)
{
int j=i+1;
while(j<n)
{
t=a[i]^a[j];
if(t>ans)
{
ans=t;
}
if(a[j]>a[i])
{
break;
}
j=r[j];
}
}
printf("%d
",ans);
return 0;
}