UPC-6358 庭师的利刃(两数与运算最大值)

题目描述
作为白玉楼的庭师,妖梦虽然不会n刀流,但是却领悟了生命二刀流。然而我也是个剑的收藏者,家里屯着n把剑,每一把剑都有一个灵魂值a[i],由于一些剑之间可能有共鸣,所以我需要两把契合度最高的剑。据妖梦所说,两把编号为i,j剑的契合度为a[i] and a[j]。如何深得剑的灵魂呢?(即求最大值)

输入
第一行一个整数n,代表藏剑数。
第二行n个整数,第i个整数表示a[i]。

输出
输出包含一个正整数,最好的两把剑的契合度。

样例输入
5
12 5 6 3 1

样例输出
4

提示
对于40%的数据 n ≤ 1,000
对于100%的数据 n ≤ 1,000,000,0 ≤ a[i] < 2^31

关于n个数中任意取两个数做某些 特殊运算 使其值最大的题目,可以说很经典了。关于与运算,可以知道必须都为1结果才为1,首先以排序然后取相邻的数相与可以得到最大结果的算法是错误的,有许多反例如455,56,7,排序后任意相邻两数相与都得0。这道题一开始这样的写法是可以A掉的,但是后来做了重判,很明显只有对二进制进行处理才能得到正解。

首先,一个ans=0,对每一个数从最高位开始遍历,对于每一个数的某一位,如果有超过一个数出现1,那么必有两数相与在那一位可以得出1的。判断每一位是否能得到1,如果可以,使结果这一位标位1,在此基础上,遍历低位,如果能在保持高位存在的情况下又能发现有数在低位上仍能取到1,说明存在数与我们刚取的最高位存在1的数相与能保证高位保持住1,并且之后的低位仍然一样。

就这样一直保证高位,取最多的低位,得到的ans一定是两数相与后出现的最大值结果。如果不存在这么一个数,或者数不足两个cnt一直为0,ans一直不加,也不会取到不存在的结果,因为保持了高位,因此值必定最大,并且存在!

这样的时间复杂度是31位遍历*每个数遍历一次(1e5),即O(31*n)

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=1e6+10;
const int inf=0x7fffffff;
const int mod = 1e9+7;
int n;
int num[maxn];
int main()
{
    while(scanf("%d",&n)!=EOF)
    {
        int ans=0;
        for(int i=1; i<=n; i++) scanf("%d",&num[i]);
        for(int i=31; i>=1; i--)
        {
            int cnt=0;
            for(int j=1; j<=n; j++)
                if(((ans&num[j])==ans)&&(num[j]&(1<<(i-1))))cnt++;
            if(cnt>1)ans+=(1<<(i-1));
        }
        printf("%d\n",ans);
    }
}
/*
5
12 5 6 3 1
3
32 85 170
2
1 9
2
20 36
5
8 16 33 72 86
2
0 1
3
511 68 96
*/

猜你喜欢

转载自blog.csdn.net/kuronekonano/article/details/81353796
UPC
今日推荐