帶刪線性基——2025.4.21 鮮花
帶刪線性基
メズマライザー feat. 初音ミク&重音テト
実際の感情はNo Think!
気付かないフリ...?
絶対的な虛実と心中
そうやって減っていく安置
傷の切り売り
脆く叫ぶ、醜態(tài)
そんなあなたにオススメ!
最高級の逃避行
やがて、甘美な罠に
釣られたものから救われる?
もはや正気の沙汰では
やっていけないこの娑婆じゃ
敢えて素知らぬ顔で
身を任せるのが最適解?
言葉で飾った花束も
心を奪えば、本物か?
全てが染まっていくような
事象にご招待
さらば!
こんな時代に誂えた
見て呉れの脆弱性
本當の芝居で騙される
矢鱈と煩い心臓の鼓動
殘機は疾うにないなっている;;
擦り減る耐久性
目の前の事象を躱しつつ
生きるので手一杯!
誰か、助けてね(^^?
「あなた段々眠くなる」
淺はかな催眠術
頭、身體、煙に巻く
まさか、數(shù)多誑かす!?
目の前で揺らぐ硬貨
動かなくなる彼方
「これでいいんだ」
自分さえも騙し騙しShut down
「あなた段々眠くなる」
淺はかな催眠術
頭、身體、煙に巻く
まさか、數(shù)多誑かす!?
目の前で揺らぐ硬貨
動かなくなる彼方...
(強制解除)
どんなに今日を生き抜いても
報われぬEveryday
もうBotみたいなサイクルで
惰性の瞬間を続けているのだ
運も希望も無いならば
尚更しょうがねえ
無いもんは無いで、諦めて
余物で勝負するのが運命
こんな時代に誂えた
見て呉れの脆弱性
本當の芝居で騙される
矢鱈と煩い心臓の鼓動
賛美はもう意味ないなっている;;
偽のカリスマ性
現(xiàn)実を直視しすぎると
失明しちゃうんだ!
だから、適度にね(^^?

考慮刪除的貢獻如何撤銷。
每個值插入線性基以后只會對插入到比他靠后的位置的數(shù)貢獻。
不妨先考慮離線的問題,離線可以直到每個值最晚是什么時候被刪掉的,當插入到某位時若當前這位的刪除時間比插入的數(shù)早,則交換。這樣可以保證所有貢獻了的數(shù)只會貢獻給比他靠前刪的。
是非常簡潔的單 \(\log\)。
Code
/* Local File
in_out/in.in
in_out/out.out
*/
#include <bits/stdc++.h>
using namespace std;
using llt = long long;
using ull = unsigned long long;
using llf = long double;
#define endl '\n'
const int N = 5e5 + 3, LG = 30;
int n, _a[N], del[N]; unordered_map<int, int> id, ct;
class Lb{
private:
int o[LG + 3], tim[LG + 3];
public:
void Ins(int v, int t){
for(int i = LG; ~i; --i) if(v & 1 << i)
if(o[i]){
if(tim[i] < t) swap(tim[i], t), swap(o[i], v);
v ^= o[i];
}else{ o[i] = v, tim[i] = t; break; }
}
int Mx(int t){
int r = 0;
for(int i = LG; ~i; --i) if(!(r & 1 << i) && tim[i] > t) r ^= o[i];
return r;
}
} lb;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> n;
for(int i = 1; i <= n; ++i){
int v; cin >> v; _a[i] = v;
if(v < 0 && !--ct[-v]) del[id[-v]] = i;
else if(v > 0 && !ct[v]++) del[i] = n + 1, id[v] = i;
}
for(int i = 1; i <= n; ++i){
if(_a[i] > 0) lb.Ins(_a[i], del[i]);
cout << lb.Mx(i) << endl;
}
}
考慮在線。
先考慮傳統(tǒng)的在線刪除線性基。
我們延續(xù)上面的思路,考慮撤銷一位的貢獻,不太簡單的分討。
設刪除的數(shù)是 \(a\)。
若刪除的數(shù)沒有插入到線性基中,則直接刪除。
若存在一個數(shù)沒被刪除 \(b\) 且其沒有插入進線性基中,并且其嘗試插入線性基時 \(a\) 異或了 \(b\),則可以用 \(b\) 平替 \(a\),為了方便我們直接將 \(b\) 刪掉即可。
注意到直接用 \(b\) 替換 \(a\) 會使得后面的數(shù)對前面造成貢獻,可以考慮去掉這部分貢獻,這樣后面的分討會簡單一點,不去也無所謂。
否則考慮其異或過的所有數(shù)中沒刪除的都存在在線性基中,我們將 \(a\) 對其他數(shù)的貢獻撤掉,若存在一個比 \(a\) 靠后的數(shù) \(b\) 被貢獻了則用 \(b\) 替換到 \(a\) 重新貢獻。
大概能實現(xiàn)到復雜度是 \(n \log^2 V\) 的。
上面的過程使用性不高,過于難寫了,有沒有優(yōu)秀的做法呢?
考慮 P11620 [Ynoi Easy Round 2025] TEST_34 的 zak 做法,即以 \(\frac 12\) 概率取出 \(\log qV + \epsilon\) 個子集,并用這些子集的異或和做線性基。
只需維護一下所有子集的全局異或和即可。
是非常簡潔的 \(\log^2\)。
Code
/* Local File
in_out/in.in
in_out/out.out
*/
#include <bits/stdc++.h>
using namespace std;
using llt = long long;
using ull = unsigned long long;
using llf = long double;
#define endl '\n'
const int N = 5e5 + 3, LG = 30, M = 60;
int n, xm[M + 3]; unordered_map<int, int> id, ct;
bool pin[M + 3][N];
class Lb{
private:
int o[LG + 3];
public:
void Clr(){ memset(o, 0, sizeof o); }
void Ins(int v){
for(int i = LG; ~i; --i) if(v & 1 << i)
if(o[i]) v ^= o[i];
else{ o[i] = v; break; }
}
int Mx(){
int r = 0;
for(int i = LG; ~i; --i) if(!(r & 1 << i)) r ^= o[i];
return r;
}
} lb;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
srand(0x7f);
cin >> n;
for(int tt = 1; tt <= n; ++tt){
int v; cin >> v;
if(v < 0 && !--ct[-v]){
int d = id[v = -v];
for(int i = 1; i <= M; ++i)
if(pin[i][d]) pin[i][d] = 0, xm[i] ^= v;
}else if(v > 0 && !ct[v]++){
id[v] = tt;
for(int i = 1; i <= M; ++i)
if(pin[i][tt] = rand() % 2) xm[i] ^= v;
}
lb.Clr();
for(int i = 1; i <= M; ++i) if(xm[i])
lb.Ins(xm[i]);
cout << lb.Mx() << endl;
}
}
P


本文來自博客園,作者:xrlong,轉載請注明原文鏈接:http://www.rzrgm.cn/xrlong/p/18838174
版權聲明:本作品采用 「署名-非商業(yè)性使用-相同方式共享 4.0 國際」許可協(xié)議(CC BY-NC-SA 4.0) 進行許可。

浙公網(wǎng)安備 33010602011771號