CS Round#53 E Maxor

Posted NINGLONG

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CS Round#53 E Maxor相关的知识,希望对你有一定的参考价值。

题意:给你N个数,你可以从中选出两个数将它们or起来得到M,求M的最大值及得到最大值的方案数。

 

刚了半个小时得到了一个貌似时O(N log max(Ai)^2)的方法,想了想发现貌似只能做出第一问,但好像改一下就能搞掉第二问,等等,复杂度炸了。。。无奈之下跑去看题解,然而题解的解法看起来十分玄妙,然而是英文我并不能读懂。。。于是我就跑去翻别人的代码,看到了Blue Mary的代码,发现很短,就去研究了一下。

我的眼睛,这特么不是暴力么。。。

#include<bits/stdc++.h>
using namespace std;
int c[1<<17],c2[1<<17];
int main(){
    int n,x;
    for(scanf("%d",&n); n--;){
        scanf("%d",&x);
        c[x]++;
    }
    for(int i=0; i<(1<<17); i++)c2[i] = c[i];
    for(int i=0; i<17; i++)for(int mask=(1<<17)-1; mask>=0; mask--)
        if(mask&(1<<i))c2[mask-(1<<i)] += c2[mask];
    for(int x = (1<<17)-1; x >= 0; x--){
        int b = 0;long long int all = 0;
        do{
            int A = c[b], B = c2[x-b];
            if(A!=0&&B!=0)all += (long long int)A*B;
        }while(b = (b-x)&x);
        if(all){
            cout << x << " " <<(all - c[x])/2 <<endl;
            break;
        }
    }
    return 0;
}
// By Blue Mary

我至今都不知道它为什么跑那么快。。。。

不过其中用到了一种枚举二进制子集的方法,这里就稍微提一下,就此题看来,相比于直接枚举集合后判断是否为子集,直接枚举子集还是能使程序效率大大提高的

Blue Mary用到的是这一种,是从小到大枚举:

int b=0;
do{
    ......
}while(b=(b-s)&s);

在ssttkkl大佬的博客中,提到了另外一种,是从大到小枚举:

for(int x=s;x;x=(x-1)&s){
     ......
}

虽然只是很小的优化,但在循环嵌套时如此枚举子集能使程序的效率翻倍提升,此题就是明证

 

正解我有空补上。。。

以上是关于CS Round#53 E Maxor的主要内容,如果未能解决你的问题,请参考以下文章

Cs Round#54 E Late Edges

[Codeforces Round #522 (Div. 2, based on Technocup 2019 Elimination Round 3)][C. Playing Piano](代码片段

[SPOJ]MAXOR

SPOJ MAXOR (分块 || 可持久化字典树 || 异或)(好题)

Unity报错:Read only asset Packages/com.xxxxx.xxx.xxxx/Editor/VSCodeDiscovery.cs.IPGSD has no meta(代码片段

Unity报错:Read only asset Packages/com.xxxxx.xxx.xxxx/Editor/VSCodeDiscovery.cs.IPGSD has no meta(代码片段