1. 程式人生 > >「線性基」學習筆記and亂口胡總結

「線性基」學習筆記and亂口胡總結

typedef www 如果 http 如何 const void 能夠 否則

還以為是什麽非常高大上的東西花了1h不到就學好了

線性基

線性基可以在\(O(nlogx)\)的時間內計算出\(n\)個數的最大異或和(不需要相鄰)。
上述中\(x\)表示的最大的數。

如何實現

定義\(p[i]\)表示在二進制下從最高位開始第一個出現\(1\)的數。
當前我們將一個數插入線性基中。
如果\(x\)的最高位的\(1\)還沒有被插入過,那麽就在這一位上插入\(x\)
如果沒有被插入過,那麽就異或上這一位上的數。
查詢操作:從最高位上開始貪心。
如果異或這一位上的數可以讓答案更大,那麽就異或,否則就異或。

貪心驗證

因為我們從高位往低位貪心,所以不需要考慮低位上的數會讓高位上的數變小的情況。

介於我們在插入的時候都是無法匹配的時候,異或上這一位上的數,那麽就保證了我們的這個數能夠達到自己能用的最大貢獻。

代碼

【洛谷模板區】

#include <bits/stdc++.h>
using namespace std;
const int BIT = 63;
const int N = 52;
typedef long long ll;
ll a[N], p[BIT + 2];
int n; 
void ins(ll x) {
    for (int i = BIT; ~i; i --) {
        if ((x >> i) == 0) continue; 
        if (!p[i]) { p[i] = x; break; }
        x ^= p[i];
    }
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    for (int i = 1; i <= n; i ++) ins(a[i]);
    for (int i = 0; i <= BIT; i ++) cout << i << " " << p[i] << endl; cout << endl;
    ll ans = 0;
    for (int i = BIT; ~i; i --) 
        if ((ans ^ p[i]) > ans) ans ^= p[i];
    cout << ans << endl;
    return 0;
}

「線性基」學習筆記and亂口胡總結