异或空间线性基

异或空间线性基

  • 2024/9/9 CCPC 预选赛碰到了基本从未见过的线性基,但是,其实没有多难

采用高斯消元法求得的一组线性基,具有以下优点:

  • 方便求第 \(k\) 大的异或和,就是选 \(2^{xxjcnt} -k\) 的二进制对应的哪些行。 (注意,代码中的 \(Query\) 函数是求第 \(k\) 小的函数)

  • 方便知道原数组是否能组成 \(0\) ,即消元后看有无全零行。

int n;
ll a[N];

bool zero;
ll p[N];
int xxjcnt;
int Gauss(){
    // 此构造线形基出的是降序排序,大小为 xxjcnt 个,编号从 1 开始
    for(int i = 1; i <= n; i++){
        p[i] = a[i];
    }
    int i, k = 1;
    ll j = (ll) 1 << 62;  // 注意不是 63;
    for(; j; j >>= 1){
        for(i = k; i <= n; i++) {
            if (p[i] & j) {
                break; // 找到了第 j 位上的 1
            }
        }
        if(i > n){
            continue; // 没有找到第 j 位上的 1
        }
        swap(p[i], p[k]);
        for(i = 1; i <= n; i++){
            if(i != k && p[i] & j){
                p[i] ^= p[k];
            }
        }
        k++;
    }
    k--;
    if(k != n){
        zero = true;
    }else{
        zero = false;
    }
    return k;
}
ll Query(ll k){
    ll ans = 0;
    if(zero) k--;
    if(!k){
        return 0;
    }
    for(int i = xxjcnt; i; i--){
        if(k&1){
            ans ^= p[i];
        }
        k >>= 1;
    }
    if(k){
        return -1; // 代表超出范围,没有查询到
    }
    return ans;
}

以及 \(main\) 函数:

void solve() {
    cin >> n;
    for(int i = 1; i <= n; i++){
        cin >> a[i];
    }
    xxjcnt = Gauss(); // 别忘了给 xxjcnt 赋值
    int q;
    cin >> q;
    for(int i = 1; i <= q; i++){
        int k;
        cin >> k;
        cout << Query(k) << endl;
    }
}
posted @ 2024-09-09 15:50  9102700  阅读(34)  评论(0)    收藏  举报