[QZSOJ4968]最大值

description

给定 n n n 个数 { a i } \{a_i\} {ai},要求从中选出两个不同的数 x , y x,y x,y,使得 x   o p   y x\ op\ y x op y 最大。

o p = o r , x o r , a n d op=or,xor,and op=or,xor,and

n ≤ 1 0 6 , a i ≤ 1 0 6 n\leq 10^6,a_i\leq10^6 n106,ai106

solution

  • x o r xor xor

我们对于所有的数二进制形式建一棵 t r i e trie trie,然后枚举一个数,在另一个上面贪心做就好了

O ( σ n ) O(\sigma n) O(σn)

  • o r or or

考虑枚举每一个数,然后对于 0 0 0 的位,看有没有一个数能够依次满足从高到低的每一位,如果有就填上,如果没有就空过去

O ( σ n ) O(\sigma n) O(σn)

  • a n d and and

从高到低枚举每一位,如果这一位上现在可以选的为 1 1 1 的数量 ≥ 2 \geq 2 2 就选上,删掉所有这一位是 0 0 0 的,否则不管

O ( σ n ) O(\sigma n) O(σn)

#include<iostream>
#include<cstring>
#include<cassert>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cstdio>
#include<vector>
#include<time.h>
#include<algorithm>
#include<climits>

using namespace std;

# define Rep(i,a,b) for(register int i=a;i<=b;i++)
# define _Rep(i,a,b) for(register int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

typedef long long ll;

const int N=(1<<20)+5;

template<typename T> void read(T &x){
   x=0;int f=1;
   char c=getchar();
   for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
   for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int t,n,op;

namespace And{
	int a[N];
	bool flag[N];
	void solve(){
		Rep(i,1,n)read(a[i]),flag[i]=true;
		int res=0;
		_Rep(s,19,0){
			int cnt=0;
			Rep(i,1,n)
				if(a[i]>>s&1&&flag[i])cnt++;
			if(cnt>=2){
				res|=1<<s;
				Rep(i,1,n)
					if(!(a[i]>>s&1))flag[i]=false;	
			}	
		}
		printf("%d\n",res);
	}
}

namespace Or{
	int a[N],sum[N];
	void solve(){
		memset(sum,0,sizeof(sum));
		Rep(i,1,n)read(a[i]),sum[a[i]]++;
		int res=0;
		Rep(s,0,19)
			for(int i=0;i<1<<20;i++)
				if(i>>s&1)sum[i^(1<<s)]+=sum[i];
		Rep(i,1,n){
			int now=a[i],yuzuki=0;
			_Rep(s,19,0){
				if(now>>s&1)continue;
				yuzuki|=1<<s;
				if(!sum[yuzuki])yuzuki^=1<<s;
			}
			now|=yuzuki;
			res=max(res,now);
		}
		printf("%d\n",res);
	}
}

namespace Xor{
	int trie[N][2],tot;
	int a[N];
	void insert(int x){
		int u=0;
		_Rep(i,19,0){
			int j=x>>i&1;
			if(!trie[u][j])trie[u][j]=++tot;
			u=trie[u][j];
		}
	}
	int ask(int x){
		int u=0,res=0;
		_Rep(i,19,0){
			int j=x>>i&1;
			j^=1;
			if(trie[u][j]){
				res|=1<<i;
				u=trie[u][j];	
			}
			else u=trie[u][j^1];
		}
		return res;
	}
	void solve(){
		memset(trie,0,sizeof(trie));
		tot=0;
		int res=0;
		Rep(i,1,n)read(a[i]),insert(a[i]);
		Rep(i,1,n)res=max(res,ask(a[i]));
		printf("%d\n",res);
	}
}

int main()
{
	read(t);
	while(t--){
		read(n),read(op);
		if(op==1)And::solve();
		if(op==2)Xor::solve();
		if(op==3)Or::solve();
	}
	return 0;
}
/*
3
5 1
1 4 5 7 9
5 2
2 3 4 5 7
5 3
9 5 4 2 1

*/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值