線性基是乙個聽起來很高階但實際上還蠻簡單的演算法,本質就類似於線性代數中的基向量,是乙個整數集合的一組線性無關的數字。說是演算法,我覺得其更偏向是一種思想。
例如一組向量:
v1=v2=
v2=三者中任意乙個都無法用另外兩者表示出來,因此它們線性無關。
舉個線性基的例子(以下為二進位制表示):
對乙個整數集合求線性基得到
(這也是一組數不是向量啊
線性基三者中任意乙個都無法通過另外兩者異或得到,且原集合中的任意乙個數都可以通過線性基中的某些數異或得到。
求線性基的過程如下:
ll lb[61];//線性基,大小取決於數字值域
int inse(ll x)//將x插入線性基,插入成功返回1,否則返回0
for (ll i=1; i<=n; i++) inse(a[i]);
for (int i=60; i>=0; i--)
if (lb[i]) res=res*2%2008;
cout實數情況的線性基,用類似高斯消元的方法操作一下,然後過程中貪心的選**最小的。
ps:注意eps的設定要大一點,否則由於計算精度不太夠,判0太嚴格會wa掉
#include #define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
const long double eps=1e-5;
int n, m, vis[510], cost[510], ans_, ans;
long double v[510][510];
int main()
a[maxn];
ll n, lb[100], ans;
ll check(ll x)
void ins(ll x)
); for (ll i=1; i<=n; i++)
if (check(a[i].id)) ans+=a[i].v, ins(a[i].id);
cout本質跟上面那題基本一樣。
根據博弈論sg函式的知識,我們知道要讓先手保證獲勝,就要保證兩個人都執行完特殊操作後,剩下的火柴堆異或起來不為0。也就是要保證先手進行完特殊操作後,剩下的火柴堆沒有異或為零的組合(否則後手者只要把組合之外的火柴都拿掉就好了)
所以要讓先手必勝,我們只要把會導致 (某些火柴堆異或為0 )的那些火柴堆拿掉就好了。為了讓拿走的火柴數最小,先按火柴數降序排列,然後逐個嘗試插入線性基,把插入失敗的火柴堆取走就行了。
#include #define maxn 50100
using namespace std;
typedef long long ll;
ll n, lb[100], num[maxn], ans;
int ins(ll x)
); for (int i=1; i<=n; i++)
if (!ins(num[i])) ans+=num[i];
cout有點巧妙的題目。
每條邊和點可以走多次,稍加觀察可以發現,假設我們本來是沿著某一路徑從1走到n,在中途其實可以走其它邊,然後走到某乙個環,轉完那個環再原路返回,此時答案只異或上了那個環上的所有值,前往那個環的路上所有值都被異或了兩次所以等於沒異或。
因此做法就是,找到一條1到n的路徑,答案就是這條路徑上的值異或起來加入線性基,再把所有環的異或加入線性基,即可構造出最大的答案。
1到n的路徑可能有多個,其實隨便用哪乙個都一樣的。因為如果存在多個1到n的路徑,它們本身也是成環的,在進行線性基的過程中會自然被替換成最優的選擇。
還有乙個問題:要找出所有環的話複雜度似乎至少得n*m?反正肯定會超時。其實只要隨便從乙個點用dfs找環就行了,雖然找的不全,但神奇的是它確實不影響答案的正確性。(個人認為是因為沒找到的環其實都是可以通過找到的環異或得到
#pragma gcc optimize(2)
#include #define maxn 50100
using namespace std;
typedef long long ll;
const ll mod=998244353;
vector> edge[maxn];
ll n, m, lb[100], res, vis[maxn], buf[maxn];
void add(ll x)
dfs(1, 0, 0);
for (ll i=61; i>=0; i--)
if (!(res&(1ll這幾題裡面唯一一道**長一點的題。據說可以用點分治搞成o(nlog2n),但是點分治不怎麼熟就還沒研究那個做法。
每次要對一條路徑上的所有值求線性基。可以把這條路徑分成兩半,u->lca(u, v)和v->lca(u,v),可以對兩段分別求線性基再合併起來。求乙個點到其某個祖先的線性基可以利用倍增的思想,對不超過logn個線性基進行合併得到。
整體來說非常像倍增求lca(我就是按照那個板子改的),複雜度單次合併是o(log2n)的,每次詢問合併logn次,所以複雜度應該是o(mlog3n)
#pragma gcc optimize(2)
#include #define maxn 20100
using namespace std;
typedef long long ll;
const ll mod=998244353;
const long double eps=1e-5;
int n, q, lg[maxn], fa[maxn][20], deep[maxn];
ll lb[maxn][20][61], buf1[61], buf2[61], num[maxn];
vectoredge[maxn];
void inse(ll x, ll *res)
merg(buf1, buf2, buf1);
inse(num[fa[x][0]], buf1);
inse(num[x], buf1);
inse(num[y], buf1);
return fa[x][0];
}int main()
dfs(1, 0);
for (ll i=1, u, v; i<=q; i++)
}
線性基學習筆記
線性基是幹嘛的呢?給定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...