线性基总结(其实就是我的模板)

Posted philo-zhou

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了线性基总结(其实就是我的模板)相关的知识,希望对你有一定的参考价值。

想知道线性基直接看大佬的https://blog.sengxian.com/algorithms/linear-basis, 我就是弄下我常用的操作。

定义

学过线代里面的“基向量”,基向量说的就是一组可以表示整个空间的向量。比如在三维空间中一个基向量就是(1,0,0) (0,1,0) (0,0,1)。线性基的定义也类似,给你一个数组a[ ],它的线性基就是一组可以表示数组a中任意一个数的一个数组p[ ]。这个表示的意思就和前面的基向量表示的意思类似,是通过p中几个元素的异或得到a中的任意一个元素。

性质

1 原序列里面的任意一个数都可以由线性基里面的一些数异或得到
2 线性基里面的任意一些数异或起来都不能得到0
3 线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的

#include<bits/stdc++.h>
#define mp make_pair
#define met(a, b) memset(a, b, sizeof(a))
#define ll long long
using namespace std;
ll p[70], newp[70], cnt;

void getp(ll x) //构建
    for(ll i = 63; i >= 0; i--)
        if(!(x>>i)) continue;
        if(!p[i])
            p[i] = x;
            break;
        
        x ^= p[i];
    


ll getmax() //求异或最大值
    ll ans = 0;
    for(int i = 63; i >= 0; i--)
        if((ans ^ p[i]) > ans) ans ^= p[i];
    
    return ans;


ll getmin() //求异或最小值
    for(int i = 0; i <= 63; i++)
        if(p[i]) return p[i];
    
    return 0;


bool judge(ll x) //判断x是不是数组a中的
    for(ll i = 63; i >= 0; i--)
        if(x>>i) x ^= p[i];
        if(!x) return 1;
    
    return 0;


void rebuild() //求第k小的准备工作
    cnt = 0;
    for(ll i = 63; i >= 0; i --)
        for(ll j = i - 1; j >= 0; j --)
            if(p[i] & (1 << j)) p[i] ^= p[j];
    
    for(ll i = 0; i <= 63; i ++)
        if(p[i]) newp[cnt++] = p[i];
    


ll getans(ll k) //求第k小
    if(k >= (1ll << cnt)) return -1;
    ll ret = 0;
    for(ll i = 63; i >= 0; i --)
        if(k & (1ll << i)) ret ^= newp[i];
    
    return ret;



int main()
    int n;  cin >> n;
    for(int i = 1; i <= n; i++)
        ll x; cin >> x;
        getp(x);
    
    rebuild();
    int m; cin >> m;
    while(m--)
        ll k; cin >> k;
        if(n != cnt) k--;  //注意这个
        cout << getans(k) << endl;
    
    return 0;

 

以上是关于线性基总结(其实就是我的模板)的主要内容,如果未能解决你的问题,请参考以下文章

LG3812 「模板」线性基 线性基

P3812 模板线性基

HDU3949 线性基模板

模板线性基

模板线性基

[洛谷3812]模板线性基