線性基學習筆記

2022-05-05 11:51:10 字數 4276 閱讀 8165

我現在大概理解線性基了。

假設你有乙個集合 \(s\),那你可以把它壓成乙個線性基 \(p\),然後使得兩個集合能異或出來的玩意完全一致。

我們是要按位操作。

假設你 \(s = \\),那你發現你的 \(p = \\) 是可以的。

然後 \(\\) 也是可以的。你要明白線性基這玩意不唯一,而且他是不同順序可能會有多種不同的線性基。

說幾個有用的性質先。

我們想象一下線性基的過程。線性基一共有 \(\log\) 位對不對。

我們考慮如果 \(x\) 的最高位為 \(2^i\) ,如果 \(p_i\) 是 0,也就是空的基的話。

我們就直接把 \(p_i = x\),這樣丟進去就好了/cy。

那麼如果 \(p_i != 0\) 怎麼辦,我們考慮到,如果 \(p_i\) 是插進去的話,那麼他也是原來的元素之一,所以和他異或一下還能是原集合能異或出來的數。

但是如果他是間接插進去的怎麼辦,它異或過其他數字!不用慌,轉化一下,由於那個位置是若干個原集合 \(s\) 的元素異或得來,當你插入這個元素,和原集合的元素異或的時候,它還是原集合能異或出來的數字對不對。

所以你整個集合都是原集合能異或出來的數字構成的,在特殊情況下,它其實就是原集合的數構成的,當你順序插入的時候。

所以先異或上,然後你的最高位就沒掉了,接著向下迴圈,直到能插進去位置,如果他插不進去?為什麼呢,因為它會變成 \(0\)。

因為你每一位都是可以控制的,控制的意思大概是指,你的 \(i\) 位如果有元素,那麼你可以選擇這一位 \(2^i\) 是選還是不選,記住,此時你只關心這個最高位。也就是從高位貪心。

如何證明線性基的元素都能異或出來原集合的元素呢?

我們再考慮,如果你丟進去 \(\\),你發現你只能異或出來 \(\) 對吧。

你發現如果你丟到線性基里,你的線性基元素也是 \(\\),還是只能構造出來這麼多。

但是如果你原集合是 \(\\) 呢?你考慮到,你丟進去6,插入成功了,線性基 \(\\)

然後再插入10,顯然能丟進去對吧,線性基 \(\\),然後我們發現原集合能構造出來是 \(\\),而你線性基構造出來的還是 \(\\)。

假如,我們要求乙個數字,能不能被乙個這個集合表示,怎麼辦,我們就假裝插入(霧)

按照插入的姿勢,直接丟進去,看有沒有乙個位置為空,如果有乙個位置為空的,直接return 1就好了,否則就return 0

我們發現 \(p_i\) 的最高位是 \(2^i\) 對吧,且其他元素的最高位都不和這個重複。

我們倒著取(這裡指倒著迴圈),如果 \(p_i\) 這一位存在,我們自然是不取這乙個基的,否則就取過來,因為你乙個 \(2^i \geq p_\),易證,不證明了。

然後你可以有效的控制 \(2^i\) 這一位到底有沒有,因為你 \(p_i\) 一定存在 \(i\) 這一位,但是你 \(p_j [j \geq i]\) 也可能存在 \(i\) 這一位所以不能直接取,要取乙個 \(max(ans , ans \oplus p_i)\)。

如果我們想求 \(k\) 大 \(k\) 小的話,那麼我們要去關心 \(i\) 必須不能被比他大的元素干擾,所以我們要消除這個貢獻也就是 \(p_i \& (2^j) [j < i]\) 的時候 \(p_i \oplus p_j\)

loj 有個題可以去試試

**長這個樣子

p3812 【模板】線性基

// by isaunoya

#include using namespace std;

#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)

#define rep(i, x, y) for (register int i = (x); i >= (y); --i)

#define int long long

const int _ = 1 << 21;

struct i

inline i& operator>>(int& x)

inline i& operator>>(double& x)

x = sign ? x : -x;

return *this;

} inline i& operator>>(char& x)

inline i& operator>>(string& s)

} in;

struct o

inline o& operator<<(int x)

inline o& operator<<(char x)

inline o& operator<<(string s)

} out;

#define pb emplace_back

#define fir first

#define sec second

int n, a[64], p[64];

signed main()

}} int ans = 0;

for (int i = 50; ~i; --i) ans = max(ans, ans ^ p[i]);

out << ans << '\n';

return out.flush(), 0;

}

p4151 [wc2011]最大xor和路徑

找個出所有簡單環,這樣就可以和原有路徑抵消掉

最後求異或,沒了

// by isaunoya

#include using namespace std;

#define rep(i, x, y) for (register int i = (x); i <= (y); ++i)

#define rep(i, x, y) for (register int i = (x); i >= (y); --i)

#define int long long

const int _ = 1 << 21;

struct i

inline i& operator>>(int& x)

inline i& operator>>(double& x)

x = sign ? x : -x;

return *this;

} inline i& operator>>(char& x)

inline i& operator>>(string& s)

} in;

struct o

inline o& operator<<(int x)

inline o& operator<<(char x)

inline o& operator<<(string s)

} out;

#define pb emplace_back

#define fir first

#define sec second

template inline void cmax(t& x, const t& y)

template inline void cmin(t& x, const t& y)

int n, m;

const int n = 5e4 + 10;

const int m = 1e5 + 10;

int cnt = 0, head[n];

struct edge e[m << 1];

int d[n], p[65];

bool vis[n];

void add(int u, int v, int w) , head[u] = cnt;

e[++cnt] = , head[v] = cnt;

}void insert(int val)

}void dfs(int u, int cur)

}int query(int val)

signed main()

dfs(1, 0);

out << query(d[n]) << '\n';

return out.flush(), 0;

}

留一些坑。

洛谷p3857 [tjoi2008]彩燈

洛谷p4301 [cqoi2013]新nim遊戲

cf895c square subsets

洛谷p4570 [bjwc2011]元素

洛谷p3265 [jloi2015]裝備購買

洛谷p3292 [scoi2016]幸運數字

洛谷p4151 [wc2011]最大xor和路徑

cf724g xor-matic number of the graph

cf938g shortest path queries

線性基學習筆記

線性基是幹嘛的呢?給定n個數,求所有數的異或和最大是多少?求解這類問題的時候,就需要線性基了 個人感覺線性基本身就一種貪心。首先定義ba se i bas e i 表示最高位1在i位的數是什麼 對於新進來的數tm p tmp 我們先找出他最高位上的1,假設為第 j j 位,然後看一下ba se j ...

線性基 學習筆記

includeusing namespace std using ll long long const int maxn 5e5 5 原來的數 const int maxbit 63 ll a maxn 原來的數 ll p maxbit p j 第j位為最高位1的數 最高位1在第j位的數 int m...

線性基 學習筆記

按位計算,如果相同記為0,不同記為1。如果,a b c,c b a 交換律結合律 對於任何數,x x 0,x 0 x 對 於一 段序列a n,異或 和為a1 a2 an 對於一段序列a n,異或和為a 1 a 2 a n 對於一段序列 an 異或和為 a1 a2 an 設t s,所有 這樣的子 集t...