XOR HDU - 3949 (线性基 求异或第k小)

题目链接

题意:n个数,q个询问,问这n个数的子集异或和中,第k小的异或和等于多少。

讲解视频

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=10005;
const int maxbit=63;
ll A[N];
ll P[maxbit];
ll L[maxbit];
int main(){
    int t;
    scanf("%d",&t);
    for(int kase=1;kase<=t;++kase){
        printf("Case #%d:\n",kase);
        int n;
        scanf("%d",&n);
        for(int i=1;i<=n;++i){
            scanf("%lld",&A[i]);
        }

        memset(P,0,sizeof P);

        //处理出线性基P
        for(int i=1;i<=n;++i){
            for(int j=maxbit-1;j>=0;--j){//63位longlong
                if((A[i]>>j)&1){
                    if(P[j]==0){
                        P[j]=A[i];
                        break;
                    }else{
                        A[i]^=P[j];
                    }
                }
            }
        }

        //为了求第k小 先对线性基作这样的处理
        for(int i=maxbit-1;i>=0;--i){// 对于P[i](最高位1在第i位的某线性基)  对每一个 最高位1的位置大于i的数 P[j=i+1,maxbit) 从[i+1,maxbit) 如果第i位是1 就异或上P[i]
            for(int j=i+1;j<maxbit;++j){
                if( ( (P[j]>>i) &1 ) )//P[j]第i位是1
                    P[j]^=P[i];//消掉P[j]第i位的1
                    //P[i]变成了P数组中唯一的 第i位是1的数 P中其他数的第i位都是0
            }
        }

        int m=0;
        for(int i=0;i<maxbit;++i){
            if(P[i]){
                L[m++]=P[i];//1在第i位的线性基P[i] 按i从小到大存在L[]里
            }
        }
        //求第k小 对k的二进制 枚举L

        int Q;
        scanf("%d",&Q);
        while(Q--){
            ll k;
            scanf("%lld",&k);//第k小
            if(n!=m) k--;//如果数组的元素个数n不等于线性基的个数m 能异或出0 0是第1小
            if( k >= 1LL<<m ){//m个线性基能异或出的数量 2^m-1
                puts("-1");
            }else{
                ll ans=0;
                for(int j=0;j<maxbit;++j){
                    if((k>>j)&1)//二进制枚举 从低到高 能求出第k小
                        ans^=L[j];
                }
                printf("%lld\n",ans);
            }
        }
    }
    return 0;
}

绝了,已全部理解,多不容易,一定要牢牢背住。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值