链接:https://www.nowcoder.com/acm/contest/156/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≤ 105, a1... an < 231
#include<iostream>
#include<algorithm>
#include<string>
#include<map>//int dx[4]={0,0,-1,1};int dy[4]={-1,1,0,0};
#include<set>//int gcd(int a,int b){return b?gcd(b,a%b):a;}
#include<vector>
#include<cmath>
#include<stack>
#include<string.h>
#include<stdlib.h>
#include<cstdio>
#define mod 1e9+7
#define ll long long
#define maxn 100005
#define MAX 1000000000
#define ms memset
using namespace std;
/*
题目大意:(中文题目,不解释了)
这题主要是技巧,
一个是如何判断一个数是(1<<i)的呢?
需要用到树状数组里面的lowbit知识,
有了这个判定就方便多了
比赛时这题搞烦了,主要是对时间复杂度的不敏感
还特地用节点存储排了序,导致好多错误。。。。
仔细想想暴力一点就10^6的复杂度。
下面讨论里面的数学。
对于i位开头是1的所有数,
如果这些数中有任意两个相与其结果为(1<<i)
那么贪心可得,这个范围的数都可以选,但不能比这个小的任何数。
那么倒退i,让1<<i的范围倒退即可,逐步判断,一旦发现了一定是最佳的选择。
*/
int data[maxn],n;
int ans[maxn],cnt=0;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&data[i]);
for(int i=30;i>=0;i--)
{
cnt=0;
int s=(1ll<<31)-1;
for(int j=1;j<=n;j++)
if(data[j]>>i & 1) s&=data[j],ans[cnt++]=data[j];
if( (s&-s)==(1<<i) ) break;
}
cout<<cnt<<endl;
for(int i=0;i<cnt;i++)
{
if(i==0) cout<<ans[i];
else cout<<" "<<ans[i];
}
cout<<endl;
return 0;
}