description
给定 nnn 个数 {ai}\{a_i\}{ai},要求从中选出两个不同的数 x,yx,yx,y,使得 x op yx\ op\ yx op y 最大。
op=or,xor,andop=or,xor,andop=or,xor,and
n≤106,ai≤106n\leq 10^6,a_i\leq10^6n≤106,ai≤106
solution
- xorxorxor
我们对于所有的数二进制形式建一棵 trietrietrie,然后枚举一个数,在另一个上面贪心做就好了
O(σn)O(\sigma n)O(σn)
- ororor
考虑枚举每一个数,然后对于 000 的位,看有没有一个数能够依次满足从高到低的每一位,如果有就填上,如果没有就空过去
O(σn)O(\sigma n)O(σn)
- andandand
从高到低枚举每一位,如果这一位上现在可以选的为 111 的数量 ≥2\geq 2≥2 就选上,删掉所有这一位是 000 的,否则不管
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
*/
这篇博客介绍了如何针对不同运算(异或、或、与)在给定的整数集合中选择两个数以最大化操作结果。使用了trie树、贪心策略和位运算技巧,分别提供了O(σn)的时间复杂度解决方案。

被折叠的 条评论
为什么被折叠?



