现在的位置: 首页 > 综合 > 正文

codechef And Operation

2018年04月24日 ⁄ 综合 ⁄ 共 1374字 ⁄ 字号 评论关闭
文章目录

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:

4
2
4
8
10

Output:

8

Explanation

2 and 4 = 0
2 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;
}

抱歉!评论已关闭.