与运算 递归

【题目描述】
给定 n 个数,找出两个,使得它们经过与运算后结果最大。
注意,选出来的两个数在原数组中的位置不能一样,但是数值可以一样。
【输入格式】
第一行一个整数 n,表示数字个数。
第二行 n 个数,表示给定的数。
【输出格式】
一个整数表示答案。
【样例输入】
3
1 2 1
【样例输出】
1
【数据范围】
对于 20%的数据点,n <= 1000
对于另外 20%的数据点,只有 0 和 1
对于 100%的数据点,n <= 100000, 0 <= 数值 <= 10^9


 

我们知道当当前位都是1时与出来才是1,所以我们考虑从位数高的地方开始统计。

如果当前位数字数量大于2,那么就符合条件,然后递归继续找低位有没有满足条件的。

代码:

 

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>

#define ll long long
#define il inline
#define db double

using namespace std;

il int gi()
{
	int x=0,y=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
		{
			if(ch=='-')
				y=-1;
			ch=getchar();
		}
	while(ch>='0'&&ch<='9')
		{
			x=x*10+ch-'0';
			ch=getchar();
		}
	return x*y;
}

int point[100045];

int stackk[100045];

int stack[100045];

int ci[45];

int num[31][100005];

int s[31];

int er[100005][31];

int check(int now,int tot)//now是当前2的几次方,tot是有多少数满足
{
	//printf("now=%d tot=%d\n",now,tot);
	if(now==0)
		return 1;
	for(int next=1;now-next>=0;next++)
		{
			int cnt=0;
			for(int i=1;i<=tot;i++)
				if(er[stack[i]][now-next])
					stackk[++cnt]=stack[i];
			if(cnt>=2)
				{
					for(int i=1;i<=cnt;i++)
						stack[i]=stackk[i];
					return ci[now]+check(now-next,cnt);
				}
		}
	return ci[now];
}

int main()
{
	freopen("and.in","r",stdin);
	freopen("and.out","w",stdout);

	int n=gi();

	ci[0]=1;
	for(int i=1;i<=30;i++)
		ci[i]=ci[i-1]*2;

	int x;
	bool flag=0;
	for(int i=1;i<=n;i++)
		{
			x=gi();
			if(x!=0)
				flag=1;
			point[i]=x;
			for(int j=30;j>=0;j--)
				if(x>=ci[j])
					{
						x-=ci[j];
						er[i][j]=1;
						num[j][++s[j]]=i;
					}
		}
   
	int now=30;
	while(s[now]<2&&now>=0)
		{
			now--;
		}

	for(int i=1;i<=s[now];i++)
		stack[i]=num[now][i];

	if(flag)
		printf("%d\n",check(now,s[now]));
	else
		printf("0\n");

	return 0;
}

 

posted @ 2017-10-20 16:18  GSHDYJZ  阅读(123)  评论(0编辑  收藏  举报