线性基

    将每个整数看成是一个向量,这些整数的线性基是这些整数的极大异或无关组,每个整数都能唯一的通过线性基内的数异或出来,整数直接互相异或的结果也能通过线性基异或出来,线性基的所有异或结果能通过这些整数异或出来.

构造

    线性基是一个一维数组,下标表示二进制位,每个二进制位对应一个线性基的整数向量.

    构造时将每个整数逐个插入线性基.设插入值为x.

    从高位到低位检查x,为0的位直接跳过,否则检查线性基该位是否已有整数向量,若有则将x异或该向量并跳过该位,否则有两种处理方法.

    1.构造阶梯型:直接将x赋给线性基这一位,结束插入操作.

    2.构造最简阶梯型:利用低于这一位的整数向量先把x中低于这一位的1消成0,再用x把高于这一位的整数向量中这一位的1消成0

,最后将x赋给线性基的这一位,结束插入操作.

    整数子集异或最大值=最简阶梯型线性基所有整数向量异或值

    整数子集异或最大值=从高位到低位将能使答案不断变大的上三角线性基中的整数向量异或值异或起来

    整数子集异或最小值=最简阶梯型线性基最小的整数向量

    某个整数x能被这些整数异或出来=不能插入线性基

    从这些整数中选任意个与x异或的最大值=从高到低位将能使答案不断变大的最简阶梯型线性基中的整数向量与x异或

#include<iostream>//构造最简阶梯型线性基
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
ll lb[64];
void insert(ll x)
{
    for(int i=50;i>=0;--i)
    {
        if(!(x>>i&1))continue;
        if(lb[i]) 
        {
            x^=lb[i];
            continue;
        }
        for(int j=i-1;j>=0;--j)
            if(x>>j&1)  x^=lb[j];
        for(int j=i+1;j<=50;++j)
            if(lb[j]>>i&1)  lb[j]^=x;
        lb[i]=x;
        break;
    }
}
int main()
{
  //  freopen("1.txt","r",stdin);
    int n;cin>>n;
    for(int i=0;i<n;++i)
    {
        ll a;scanf("%lld",&a);
        insert(a);
    }
    ll ans=0;
    for(int i=0;i<=50;++i)
    {
        ans^=lb[i];
    }
    cout<<ans<<endl;
    return 0;
}

 线性基异或第k小值

  k从0开始,计算出线性基后需要将最简阶梯型线性基中的0去掉再从小到大排序,再将k的二进制位为1的对应位置的排序后数组内的整数向量异或起来.

//k从0开始,计算出线性基后需要将线性基中的0去掉再从小到大排序,再将k的二进制位为1的对应位置的排序后数组内的整数向量异或起来.
//本题第k小从1开始
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
typedef long long ll;
ll lb[64];
vector<ll>num;
int add(ll x)
{
    for(int i=63;i>=0;--i)
    {
        if(!(x>>i&1))continue;
        if(lb[i]) x^=lb[i];
        else
        {
            for(int j=i-1;j>=0;--j)
            {
                if(x>>j&1) x^=lb[j];
            }
            for(int j=i+1;j<=63;++j)
                if(lb[j]>>i&1) lb[j]^=x;
            lb[i]=x;
            return 1;
        }
    }
    return 0;
}
ll Pow(ll x,int y)
{
    ll res=1;
    while(y)
    {
        if(y&1) res=res*x;
        x=x*x;
        y>>=1;
    }
    return res;
}
int main()
{
   // freopen("1.txt","r",stdin);
    int t;cin>>t;
    int times=1;
    while(t--)
    {
        int n;cin>>n;
        memset(lb,0,sizeof(lb));
        int f=0;
        int s=0;
        for(int i=0;i<n;++i)
        {
            ll a;scanf("%lld",&a);
            if(!add(a))
            f=1;
            else
            s++;
        }
        num.clear();
        for(int i=0;i<64;++i)
        if(lb[i]) num.push_back(lb[i]);
        sort(num.begin(),num.end());
        int q;cin>>q;
        printf("Case #%d:\n",times++);
        while(q--)
        {
            ll k;scanf("%lld",&k);
            if(f)
            {
                k--;
            if(Pow(2,s)<k+1)
            {
                printf("-1\n");
                continue;
            }
            }
            else if(Pow(2,s)-1<k)
            {
                printf("-1\n");
                continue;
            }
            ll ans=0;
            for(int i=0;i<=63&&i<num.size();++i)
            {
                if(k>>i&1)
                ans^=num[i];
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

 线段树区间线性基

//查询O(logn*32*32)
const int N=1e4+10;
int tree[N*4][32];
int sl[32];
void add(int x,int lb[])
{
    for(int i=31;i>=0;--i)
    {
        if(!(x>>i&1))continue;
        if(lb[i])x^=lb[i];
        else
        {
            lb[i]=x;
            return;
        }
    }
}
void build(int now,int l,int r)
{
    if(l==r)
    {
        int a;scanf("%d",&a);
        add(a,tree[now]);
        return;
    }
    int mid=(l+r)>>1;
    build(now<<1,l,mid);
    build(now<<1|1,mid+1,r);
    for(int i=0;i<32;++i)
    {
        tree[now][i]=tree[now<<1][i];
        add(tree[now<<1|1][i],tree[now]);
    }
}
void query(int now,int l,int r,int x,int y)
{
    if(x<=l&&r<=y)
    {
        for(int i=0;i<32;++i)
        add(tree[now][i],sl);
        return;
    }
    int mid=(l+r)>>1;
    if(y<=mid)
    query(now<<1,l,mid,x,y);
    else if(x>mid)
    query(now<<1|1,mid+1,r,x,y);
    else
    {
        query(now<<1,l,mid,x,y);
        query(now<<1|1,mid+1,r,x,y);
    }
}
int main()
{
 //   freopen("1.txt","r",stdin);
    int t;cin>>t;
    while(t--)
    {
        memset(tree,0,sizeof(tree));
        int n,q;scanf("%d%d",&n,&q);
        build(1,1,n);
        while(q--)
        {
            int l,r;scanf("%d%d",&l,&r);
            for(int i=0;i<32;++i) sl[i]=0;
            query(1,1,n,l,r);
            int ans=0;
            for(int i=31;i>=0;--i)
            ans=max(ans,ans^sl[i]);
            printf("%d\n",ans);
        }
    }
    return 0;
}

 

### 关于线性基的C++实现 线性基是一种用于处理向量空间中线性无关性的数据结构,在许多竞赛编程问题中有广泛应用。以下是基于用户需求的一个完整的线性基 C++ 实现代码示例: #### 线性基的核心概念 线性基是一组数,能够通过异或操作表示某个集合内的所有可能数值组合。对于给定的一组整数 \( S \),其线性基可以唯一确定这些整数所能构成的所有 XOR 值。 ```cpp #include <bits/stdc++.h> using namespace std; const int MAX_BITS = 60; // 根据题目范围调整大位数 struct LinearBasis { long long basis[MAX_BITS]; // 存储线性基数组 void insert(long long x) { // 插入一个新元素到线性基中 for (int i = MAX_BITS - 1; i >= 0; --i) { if (!(x >> i)) continue; if (!basis[i]) { basis[i] = x; break; } x ^= basis[i]; } } bool contains(long long x) const { // 判断某值是否能由当前线性基生成 for (int i = MAX_BITS - 1; i >= 0; --i) { if ((x >> i) & 1 && !basis[i]) return false; x ^= basis[i]; } return true; } long long max_xor() const { // 计算线性基大XOR值 long long res = 0; for (int i = MAX_BITS - 1; i >= 0; --i) { if ((res ^ basis[i]) > res) res ^= basis[i]; } return res; } vector<long long> get_all_elements() const { // 枚举线性基可生成的所有不同值 vector<long long> elements{0}; for (int i = 0; i < MAX_BITS; ++i) { if (!basis[i]) continue; int sz = elements.size(); for (int j = 0; j < sz; ++j) { elements.push_back(elements[j] ^ basis[i]); } } sort(elements.begin(), elements.end()); return elements; } }; // 测试部分 void test_linear_basis() { LinearBasis lb; vector<long long> nums = {8, 4, 12}; // 输入一组数 for (auto num : nums) lb.insert(num); cout << "Max XOR value: " << lb.max_xor() << "\n"; // 输出大XOR值 } ``` 以上代码实现了线性基的主要功能,包括插入、查询是否存在特定值以及计算大 XOR 值等功能[^3]。 #### 使用说明 1. **初始化**:创建 `LinearBasis` 对象来存储线性基。 2. **插入元素**:调用 `insert(x)` 方法将新的整数 \( x \) 添加至线性基中。 3. **判断存在性**:使用 `contains(x)` 来验证某一值是否可以通过现有线性基中的元素异或得到。 4. **求大 XOR 值**:调用 `max_xor()` 获取当前线性基所能产生的大 XOR 结果。 5. **枚举所有可能值**:利用 `get_all_elements()` 返回线性基所覆盖的所有可能值列表。 此实现适用于大多数涉及二进制运算的问题场景,并具有较高的效率和灵活性。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值