#2909. 最大值(maximum)

题目描述

Alice和Bob是好朋友,这天他们正在玩一个找最大值的游戏。

Alice给出一个含有n个正整数的序列A(下标从1开始编号),以及一个位运算操作符op,她想要Bob回答所有Ai op Aj(1≤i

运算符op可能为与运算(and)、或运算(or)、异或运算(xor)。

Bob并不会解答这个问题,你能帮帮他吗?

输入格式

第一行包含一个整数T,表示数据组数。

接下来T组数据,每组数据第一行包含两个整数n,c.其中n表示序列长度,c表示操作符。

当c=1时,操作符op为与运算(and).

当c=2时,操作符op为异或运算(xor).

当c=3时,操作符op为或运算(or).

每组数据第二行包含n个整数,第i个整数表示序列中的数Ai.

输出格式

每组数据输出一行一个整数表示Ai op Aj(1≤i

样例
样例输入

3
5 1
1 4 5 7 9
5 2
2 3 4 5 7
5 3
9 5 4 2 1

样例输出

5
7
13

数据范围与提示

【样例2】maxmum.rar

【数据范围】

有30%的数据:n≤1000

另有30%的数据:Ai≤1024

另有5%的数据:c均为1

另有25%的数据:c均为2

另有5%的数据:c均为3

100%的数据: 1≤T≤6 1 \leq T \leq 6 1≤T≤6 , 2≤n≤105 2 \leq n \leq 10^5 2≤n≤105 , 1≤Ai<220 1 \leq A_i <2^{20} 1≤Ai​<220 , c∈1,2,3 c \in {1,2,3} c∈1,2,3

来源

gwy
题解:
首先,对于异或,可以用trie树来实现。模板
第二,对于并,由贪心可知从最高位遍历,只要当前位有两数以上为1,那其他为0的数即可删去。
第三,对于或。可知对于某数x我们需要知道对于该数为零的位有没有其他数可以为一,而不关心是哪个数,所以可以预处理0–1<<20是否是某个数的子集。

#include
#include
#include
#include
#include
#define N 100005
using namespace std;
int trie[N*21][2],a[N],n;
int tot=1;
void build(int x){
	int p=1;
	for(int i=20;i>=0;--i){
		int ch=(x>>i)&1;
		if(!trie[p][ch])trie[p][ch]=++tot;
		p=trie[p][ch];
	}
}
int search(int x){
	int p=1,ans=0;
	for(int i=20;i>=0;--i){
		int ch=(x>>i)&1;
		if(trie[p][ch^1]){p=trie[p][ch^1];ans|=1<<i;}
		else p=trie[p][ch];
	}
	return ans;
}
int b[N];
void work_and(){
	int ans=0,res=n,cnt=0;
	memset(b,0,sizeof(b));
	for(int i=20;i>=0;--i){
		cnt=0;
		for(int j=1;j<=n;++j){
			if(!b[j]&&((a[j]>>i)&1))cnt++;
		}
		if(cnt>=2){
			for(int j=1;j<=n;++j){
				if(!b[j]&&((a[j]>>i)&1)==0)b[j]=1;
			}
			ans|=1<<i;
		}
	}
	printf("%d\n",ans);
	return ;
}
int f[(1<<21)+5];
void work_or(){
	memset(f,0,sizeof(f));
	for(int i=1;i<=n;++i){
		int now=a[i];
		for(int j=now;j;j=(j-1)&now){
			/*if(f[j]){
				now=now-j;
				j=now+1;
				continue;
			}*/
			f[j]=1;
		}
	}
	int ans=0;
	for(int i=1;i<=n;++i){
		int now=0;
		for(int j=20;j>=0;--j){
			if((a[i]>>j)&1)continue;
			if(f[now|(1<<j)])now=now|(1<<j);
		}
		ans=max(ans,a[i]|now);
	}
	printf("%d\n",ans);
	return ;
}
int main()
{
	int t;cin>>t;
	while(t--){
		int op;scanf("%d%d",&n,&op);
	//	cout<
		int ans=0;tot=1;memset(trie,0,sizeof(trie));
		for(int i=1;i<=n;++i)scanf("%d",&a[i]);
		if(op==2){
			build(a[1]);	
			for(int i=2;i<=n;++i){
				ans=max(ans,search(a[i]));
				build(a[i]);
			}
			printf("%d\n",ans);
		}
		if(op==1){
			work_and();
		}
		if(op==3){
			work_or();
		}
	}
	return 0;
}

你可能感兴趣的:(基本算法,测试,数据结构)