Problem Description
Given an array of n non-negative integers: A1, A2, …, AN. Your mission is finding a pair of integers Au, Av (1 ≤ u < v ≤ N) such that (Au and Av) is as large as possible.
And is a bit-wise operation which is corresponding to & in C++ and Java.
Input
The first line of the input contains a single integer N. The ith line in the next N lines contains the Ai.Output
Contains a single integer which is the largest value of Au and Av where 1 ≤ u < v ≤ N.Constraints
50 points:2 ≤ N ≤ 5000
0 ≤ Ai ≤ 109
50 points:
2 ≤ N ≤ 3 × 105
0 ≤ Ai ≤ 109
Example
Input:
42
4
8
10
Output:
8Explanation
2 and 4 = 02 and 8 = 0
2 and 10 = 2
4 and 8 = 0
4 and 10 = 0
8 and 10 = 8
题解
首先感谢lwher,是他让我真正领会到“正难则反”的妙用。
这道题在codechef上的数据太水了,竟然排序后只算a[i]&a[i-1]都能过!在这里给出反例,如/0011/0100/1011。
显然50分的暴力人人都会……可是我们并不能找到一种行之有效的方法去优化暴力。这时候,我们就可以想想“反过来做”:对于我们要的答案(看成2进制),一定是“每个位置不是1就是0,且越高位有1越好”(显然100比011大),那么怎么才能确定这位是否能是1呢?显然:当至少2个数这一位有1即可。所以算法如下:
我们一位一位确定答案,从高位开始。每次在现有的数里面for一遍,把这位为1的拿出来。如果个数为2个或以上,那么这一位是1,否则是0。如果是1,那么现有的数就变成我们上次拿出来的那些。复杂度 nlogK。K为数值范围
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
int n,a[300002],d[35],ans;//2^30>1000000000
void init()
{
scanf("%d",&n);
int i;
for(i=1;i<=n;i++) scanf("%d",&a[i]);
}
void find()
{
int i,j,ct,now=n,t;
for(i=30;i>=0;i--)
{ct=0;
for(j=1;j<=now;j++)
{if(a[j]&(1<<i)) ct++;}
if(ct<2) continue;
t=0; d[i]=1;
for(j=1;j<=now;j++)
{if(a[j]&(1<<i)) a[++t]=a[j];}
now=t;
}
for(i=30;i>=0;i--)
{if(d[i])
ans=ans^(1<<i);
}
printf("%d\n",ans);
}
int main()
{
init(); find();
return 0;
}