#&运算# 牛客练习赛23 C.托米的位运算

链接:https://www.nowcoder.com/acm/contest/156/C

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

托米完成了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≤ 105, a1... an < 231

 

Description:

在已知序列中选取尽可能多的一些数,使得这些数按位与后的值能整除 2^v(v >= 0) 且尽可能大。

 

Solution:

假设 a 能整除 2^v,那么也就是说将 a 换成二进制后,有且仅有最高位为1。

由于需要保证v最大,所以可以通过从高位开始枚举,第一个合法解即为答案,那么一个合法解需要满足以下两个条件:

  1. 当前枚举的 i 位为1;
  2. 并且选出的这些数(也就是枚举的第 i 位为1),低于这当前 i 位上的的数不全为1。这样就保证了在按位与运算后只有当前的 i 位为1,其他位都为0;

判断一个二进制的某一位是否为1:

假设当前数为X,如果第 i 位为1需要满足:X & (1 << (i - 1)) > 0

判断一个二进制除最高位外其余位是否为0:

假设当前数为X,如果只有最高位为1需要满足:X & ( ( 1 << (i - 1) ) - 1 ) == 0

 

Code:

#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
#define Fio ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define fopen freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout);
#define mst(a, b) memset(a, b, sizeof(a))
#define _rush() int T; cin >> T; while(T--)
#define rush() int T; scanf("%d", &T); while(T--)
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const int Mod = 1e9 + 7;
const int MaxN = 1e5 + 5;

vector <LL> vec;
LL a[MaxN];

int main()
{
	Fio;

	int n;
	cin >> n;
	for(int i = 1; i <= n; i++) cin >> a[i];
	for(int i = 30; i >= 0; i--) { //从高位开始枚举
		int p = 1 << i; //判断当前最高位i是否为1
		int pp = p - 1; //判断除最高位外其余位是否为0
		for(int j = 1; j <= n; j++) { //遍历整个a数组选取数
			if(a[j] & p) { //当前的i位为1
				vec.push_back(a[j]);
				pp &= a[j];
			}
		}
		if(pp == 0) break; //只有最高位为1,由于是从最高位开始枚举,所以第一个合法解即为答案
		vec.clear();
	}
	cout << vec.size() << endl;
	for(int j = 0; j < vec.size(); j++) cout << vec[j] << " ";
	cout << endl;
	return 0;
}

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值