有关异或问题的专题

分析:
不难发现首先我们找到二进制最大的为1的那个数maxx 我们得到的答案起码最高位是1

然后如果想要答案最大 就想尽可能使得后面为0的均为1 发现 maxx-1 就是后面位均为1

这样两者异或一定是最大的

但是可能[L,R]没有将两者包括 也就是说区间最高位都是1 那这样怎么办?

这时候发现无论我们怎么选两个数 得到的答案最高位一定是0 如果这样的话可以就不用考虑最高位就行 依次递归就好

#include<cstdio>
#include<iostream>
#define LL long long
using namespace std;
LL bitcnt(LL x){  //返回x的二进制位数 
	LL cnt=0;
	while(x)cnt++,x>>=1;
	return cnt;
}
LL solve(LL l,LL r){
	LL a=bitcnt(l),b=bitcnt(r);
	if(a!=b) return (1LL<<b)-1;  //位数相同 
	LL ans= solve(l&((1LL<<(a-1))-1),r&(((1LL<<(b-1)))-1)); 
		//位数不同,抹去最高位 
	return ans;
}
int main(){
	LL a,b;
	cin>>a>>b;
	cout<<solve(a,b); 
}

这个题数据开到非常大都可以

首先我们可以打表找规律 发现除去第一个数 剩下的就是每四个一轮回 并且这四个一轮回的第1和第3个数是确定的

这样就好办了

点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define lowbit(x) x&(-x)
#define ll long long
int main(){
	int n,start;
	cin>>n>>start;
	if(n==1){
		cout<<start<<endl;
		return 0;
	}
	n--;
	int a1=start^(start+2);
	int a2=start^(start+2)^(start+4)^(start+6);
	int t=n%4;
	if(t==3)cout<<a2<<endl;
	else if(t==1)cout<<a1<<endl;
	else if(t==2)cout<<(a1^(n*2+start))<<endl;
	else if(t==0)cout<<(a2^(n*2+start))<<endl;
     return 0;
}

两个数 按位与 按位或 按位异或 的最大值

and:就是从最高的一位向下找,如果这一位为1的数多于两个就取出这些数,然后再取出的这些数里面继续下一位的一样的处理,我就用递归写的

or:这个比较巧妙,也比较暴力,先每个数开一个数组,然后将每个数1的子集全部变为ture,然后去查找每个数,从前向后每一位为0的看有没有可以匹配的,可以就取

xor:我觉得写起来最简单的,读的时候按每一位建一个trie tree,然后查询每一个数就取反然后在里面找,可以就加这一位,不行就不加,一直走20位就可以了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<set>
#include<queue>
#include<algorithm>
#include<vector>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<stack>
#define INF 2100000000
#define ll long long
#define clr(x)  memset(x,0,sizeof(x))
#define M 100005
#define N (1<<20)

using namespace std;

int a[M];

struct tree2
{
    tree2 *lson,*rson;
    int n;
}*root,dizhi[M*21];

int t;

void add(int x)
{
    tree2 *tree=root;
    for(int i=20;i>=0;i--)
    {
        if(x&(1<<i))
        {
            if(tree->lson==NULL)tree->lson=&dizhi[++t];
            tree=tree->lson;
        }
        else
        {
            if(tree->rson==NULL)tree->rson=&dizhi[++t];
            tree=tree->rson;
        }
    }
}

int get_xor(int x)
{
    tree2 *tree=root;
    int ans=0;
    for(int i=20;i>=0;i--)
    {
        if(x&(1<<i))
        {
            if(tree->rson!=NULL)
            {
                ans+=(1<<i);
                tree=tree->rson;
            }
            else tree=tree->lson;
        }
        else
        {
            if(tree->lson!=NULL)
            {
                ans+=(1<<i);
                tree=tree->lson;
            }
            else tree=tree->rson;
        }
    }
    return ans;
}

int n,c;


int get_and(int *num,int len,int w)
{
    int s[len],sta=0;
    clr(s);
    int b=0;
    for(int i=w;i>=0;i--)
    {
        for(int j=1;j<=len;j++)
        {
            if(num[j]&(1<<i))
            {
                b++;
                s[++sta]=num[j];
            }
        }
        if(b>1)
        {
            int ret=get_and(s,sta,i-1)+(1<<i);
            return ret;
        }
        b=0;sta=0;
    }
    return 0;
}

int b[N];

int get_or()
{
    clr(b);
    for(int i=1;i<=n;i++)b[a[i]]=1;
    for(int i=0;i<=20;i++)
        for(int j=0;j<=N;j++)
            if(j&(1<<i))b[j^(1<<i)]|=b[j];
    int mx=0;
    for(int i=1;i<=n;i++)
    {
        int ans=a[i];
        int temp=0;
        for(int j=20;j>=0;j--)
            if(!(a[i]&(1<<j)))
                if(b[temp|(1<<j)])
                {
                    ans|=(1<<j);
                    temp|=(1<<j);
                }
        mx=max(mx,ans);
    }
    return mx;
}

int main()
{
    freopen("maximum.in","r",stdin);
    freopen("maximum.out","w",stdout);
    int T;
    cin>>T;
    while(T--)
    {
        cin>>n>>c;
        if(c==2)root=&dizhi[++t];
        clr(a);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            if(c==2)add(a[i]);
        }

        switch (c)
        {
            case 1:cout<<get_and(a,n,20)<<'\n';break;
            case 2:
            {
                int mx=0;
                for(int i=1;i<=n;i++)
                    mx=max(mx,get_xor(a[i]));
                cout<<mx<<'\n';
                break;
            }
            case 3:cout<<get_or()<<'\n';break;
        }
    }
    return 0;
}

第K大异或值

首先把所有数放进trie里。

然后二分答案,枚举每个数,相应地在trie上从高位开始跑,统计答案。

具体做法:当前跑到二进制第k位,已经确定了比k高的位的数字,使得每一位与当前枚举的数的异或等于mid的这一位。

如果mid第k位为0,那么这一位异或为1的一定对答案有贡献,把整个子树的答案加起来。然后继续做下一位。

时间复杂度O(nlog^2n)

#include <bits/stdc++.h>
using namespace std;
const int maxn=50005,maxm=200005,M=15;
typedef long long LL;
int n,a[maxn],l,r,mid;
LL m,ans,sum[maxm],t;
char c;
int read()
{
    for (c=getchar();c<'0' || c>'9';c=getchar());
    int x=c-48;
    for (c=getchar();c>='0' && c<='9';c=getchar()) x=x*10+c-48;
    return x;
}
void insert(int x,int num,int w)
{
    sum[x]++;
    if (w<0) return;
    if ((num&(1<<w))==0) insert(x<<1,num,w-1);else insert(x<<1|1,num,w-1);
}
int query(int x,int num,int w,int now)
{
    if (w<0) return sum[x];
    int t=((num&(1<<w))>0);
    if ((now&(1<<w))==0) return query(x<<1|t,num,w-1,now)+sum[x<<1|(t^1)];
    return query(x<<1|(t^1),num,w-1,now);
}
bool check(int x)
{
    if (!x) return 1;
    ans=0;
    for (int i=0;i<n;i++) ans+=query(1,a[i],M,x);
    if (ans>=m) return 1;
    return 0;
}
int main()
{
    scanf("%d%lld",&n,&m);
    for (int i=0;i<n;i++) insert(1,a[i]=read(),M);
    for (l=0,r=(1<<(M+1))-1,mid=r>>1;l<r;mid=l+r>>1)
        if (check(mid)) l=mid+1;else r=mid;
    if (!check(l)) l--;
    printf("%d\n",l);
    fclose(stdin); fclose(stdout);
    return 0;
}
posted @   wzx_believer  阅读(33)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示