1. 程式人生 > >牛客練習賽23-C-托米的位運算(模擬)

牛客練習賽23-C-托米的位運算(模擬)

題目描述

托米完成了1317的上一個任務,十分高興,可是考驗還沒有結束
說話間1317給了托米 n 個自然數 a1... an, 托米可以選出一些帶回家,但是他選出的數需要滿足一些條件
設托米選出來了k 個數 b1,b2... bk, 設這個數列 b 的給值為 b 中所有數按位與的結果,如果你能找到一個整除 b 的最大的 2v,(v≥ 0), 則設定 v 為這個數列的給價,如果不存在這樣的 v,則給價值為 -1, 1317 希望托米在最大化給價的情況下,最大化 k

輸入描述:

第一行輸入一個整數 n, 第二行輸入 a1...an

輸出描述:

第一行輸出最大的整數 k, 第二行輸出 k 個整數 b1... bk, 按原數列的相對順序輸出 (如果行末有額外空格可能會格式錯誤)

示例1

輸入

複製

5
1 2 3 4 5

輸出

複製

2
4 5

備註:

n≤ 10^5, a1... an < 2^31

題解:與的特點是某位為0,則只要添上這個數,最後相與的結果這一位一定是0,因此我們暴力數列的給價

從31到0,每次只有陣列中該位為1才可能對答案有貢獻,並且其他位一定不影響(如果最後答案成立的話)。


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long
ll n,a[100005],b[100005];
int main(void)
{
	int k;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	for(int i=31;i>=0;i--)
	{
		k=0;
		ll ans=((1<<i)-1);
		for(int j=1;j<=n;j++)
		{
			if(a[j]&(1<<i))
				ans=(ans&a[j]),b[++k]=a[j];
		}
		if((ans&-ans)==(1<<i))//x&(-x)返回x與2^64的最大公約數
			break;
	}
	printf("%d\n",k);
	for(int i=1;i<k;i++)
		printf("%lld ",b[i]);
	printf("%lld\n",b[k]);
	return 0;
}