P5283 異或粽子(Trie)
阿新 • • 發佈:2021-08-05
目錄
Description
有 n 個數,任選兩個數 \(1<=L<=R<=n\),使得 \(k\) 個 \([L,\; R]\) 的區間異或和最大
State
\(1<=n,\; k <=5*10^5\)
\(0<=a[i]<=4294967295\)
Input
3 2
1 2 3
Output
6
Solution
在這裡提供三種解法,程式碼為第三種解法:
1.對於每一個 \(i∈[1,\; n]\) 在區間 \([i,\; n]\) 內尋找一個位置 \(id\) ,使得 \(sum[id]⊕sum[i]\) 最大,將這 \(n\) 個最大值放入堆中,依次取出,再將區間分為 \([i,\; id - 1]\) 和 \([id + 1, \; n]\) 即可,直至挑選 \(k\) 個
2.由於\(\forall i,\; \exists j,\; sum[i]⊕sum[j]\) 最大,但是由於題目中 \(i<=j\)
3.類似於解法 2, 但是可以將 \(j\) 固定於 \([i, \; n]\) 區間上尋找每一個 \(i\) 的前 \(k\) 大值,這時就需要可持久化 \(Trie\) 了,也因為如此,其需要的空間比上面兩種要更大一點 \((hack)\)
Code
const int N = 5e5 + 5; ll n, m, _; int i, j, k; ll a[N]; int ch[N * 40][2], sz[N * 40]; int tot = 0, root[N]; void ins(int &x, int y, ll c) { x = ++ tot; int nx = x, ny = y; for(int i = 33; ~ i; i --){ int id = (c >> i) & 1; ch[nx][0] = ch[ny][0]; ch[nx][1] = ch[ny][1]; ch[nx][id] = ++ tot; nx = ch[nx][id]; ny = ch[ny][id]; sz[nx] = sz[ny] + 1; } } ll query(int rk, ll c, int x, int y) { ll ans = 0; for(int i = 33; ~ i; i --){ int id = (c >> i) & 1; int size = sz[ch[y][!id]] - sz[ch[x][!id]]; if(size >= rk){ ans |= (1ll << i); x = ch[x][!id]; y = ch[y][!id]; } else{ rk -= size; x = ch[x][id]; y = ch[y][id]; } } return ans; } struct Node { int rk, id; ll val; int l, r; Node(){} Node(int id, int rk){ this -> id = id; this -> rk = rk; l = id, r = n; val = query(rk, a[id], root[l], root[r]); } bool operator<(Node o) const{ return val < o.val; } }; signed main() { //IOS; while(~ sdd(n, k)){ rep(i, 1, n){ sll(a[i]); a[i] ^= a[i - 1]; } priority_queue<Node> q; ins(root[0], root[0], 0ll); rep(i, 1, n){ ins(root[i], root[i - 1], a[i]); } rep(i, 0, n - 1){ q.push(Node(i, 1)); } ll ans = 0; rep(i, 1, k){ Node top = q.top(); q.pop(); ans += top.val; if(top.val != 0) q.push(Node(top.id, top.rk + 1)); } pll(ans); } return 0; }