1. 程式人生 > >CS Round#53 E Maxor

CS Round#53 E Maxor

一個 得到 long strong () 方案 代碼 scan bre

題意:給你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