【线性基】HDU3949[XOR]题解

本文介绍了一种解决特定组合数学问题的高效算法——找出一组数字中所有非空子集的异或和中第K小的值。通过构建线性基并利用位运算特性,该算法能在较短时间内找到解决方案。若不存在足够数量的有效子集,则返回特殊值-1。

题目概述

给出 nn 个数,求选出的非空集合中异或和第 k 小的异或和(异或和相同算一次),没有 kk 个输出 1

解题报告

如果构造线性基时将矩阵消成对角矩阵,得到的线性基就有一个很棒的性质:最高位为 ii 的数至多只有一个,且其他数第 i 位为 0 (即使得到的线性基无法表示为对角矩阵,只要按照消成对角矩阵的方法去构造,也满足这个性质)。

因为最高位为 ii 的数至多只有一个,所以挑出矩阵中的非零项 {Bm}m1i=0Bi(k and 2i)∑i=0m−1Bi(k and 2i) 就是答案。

解题报告

#include<cstdio>
#include<cstring>
typedef long long LL;
using namespace std;
const int Log=60;

int te,n,Q;LL M[Log],B[Log];

inline void Insert(LL x){
    for (int j=Log;~j;j--)
        if (x>>j&1)
            if (M[j]) x^=M[j]; else{
                M[j]=x;for (int k=0;k<j;k++) if (M[j]>>k&1) M[j]^=M[k];
                for (int k=j+1;k<Log;k++) if (M[k]>>j&1) M[k]^=M[j];break;
            }

}
int main(){
    freopen("program.in","r",stdin);
    freopen("program.out","w",stdout);
    for (int i=(scanf("%d",&te),1);i<=te;i++){
        printf("Case #%d:\n",i);scanf("%d",&n);memset(M,0,sizeof(M));B[0]=0;
        for (int i=1;i<=n;i++) {LL x;scanf("%lld",&x);Insert(x);}
        for (int i=0;i<Log;i++) if (M[i]) B[++B[0]]=M[i];
        for (scanf("%d",&Q);Q;Q--){
            LL x,ans=0;int pos=0;scanf("%lld",&x);x-=B[0]<n;
            while (x) {pos++;if (x&1) ans^=B[pos];x>>=1;}
            if (B[0]<pos) puts("-1"); else printf("%lld\n",ans);
        }
    }
    return 0;
}
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值