[十二省联考 2019] 异或粽子(可持久化字典树 + 二叉堆)
problem
luogu-P5283
小粽是一個喜歡吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 nnn 種互不相同的粽子餡兒,小粽將它們擺放為了一排,并從左至右編號為 111 到 nnn。
第 iii 種餡兒具有一個非負(fù)整數(shù)的屬性值 aia_iai?。
每種餡兒的數(shù)量都足夠多,即小粽不會因為缺少原料而做不出想要的粽子。
小粽準(zhǔn)備用這些餡兒來做出 kkk 個粽子。
小粽的做法是:選兩個整數(shù)數(shù) l,rl,rl,r,滿足 1?l?r?n1 \leqslant l \leqslant r \leqslant n1?l?r?n,將編號在 [l,r][l, r][l,r] 范圍內(nèi)的所有餡兒混合做成一個粽子,所得的粽子的美味度為這些粽子的屬性值的異或和。
小粽想品嘗不同口味的粽子,因此它不希望用同樣的餡兒的集合做出一個以上的粽子。
小粽希望她做出的所有粽子的美味度之和最大。請你幫她求出這個值吧!
solution
考慮如何快速求得對于 iii 而言的一段往前的連續(xù)段異或最大值。
顯然前綴異或和后,轉(zhuǎn)化成求 j<i,aj⊕aij<i,a_j\oplus a_ij<i,aj?⊕ai? 的最大值。
字典樹基本應(yīng)用。
接下來又怎么辦呢?這么多個區(qū)間。
考慮暴力是把所有區(qū)間異或和求出來然后扔進(jìn)堆里面,選權(quán)值前 kkk 大的。
這里我們找到了對于每個 iii 的最佳位置 jjj,但是還有可能第二優(yōu)秀的位置比其它 iii 的最佳位置權(quán)值更大。
我們又要避免找到重復(fù)的區(qū)間。
這里類比《超級鋼琴》的做法。
記錄下最佳位置的選擇,然后把可選區(qū)間 [l,r][l,r][l,r] 分成兩段 [l,j],(j,r)[l,j],(j,r)[l,j],(j,r)。
也就需要實現(xiàn)可持久化字典樹了。
code
#include <bits/stdc++.h> using namespace std; #define int long long #define maxn 500005 int root[maxn], cnt; struct tree { int son[2], id, cnt; }t[maxn * 80]; void insert( int lst, int now, int x, int id ) {root[now] = ++ cnt;now = root[now], lst = root[lst];t[now] = t[lst]; t[now].cnt ++;for( int i = 32;~ i;i -- ) {int k = x >> i & 1;t[now].son[k] = ++ cnt;now = t[now].son[k];lst = t[lst].son[k];t[now] = t[lst];t[now].cnt ++;}t[now].id = id; } int query( int L, int R, int x ) {for( int i = 32;~ i;i -- ) {int k = x >> i & 1;if( t[t[R].son[k ^ 1]].cnt - t[t[L].son[k ^ 1]].cnt )R = t[R].son[k ^ 1], L = t[L].son[k ^ 1];elseR = t[R].son[k], L = t[L].son[k];}return t[R].id; } struct node { int l, r, x, p, val; bool operator < ( const node &v ) const {return val < v.val;} }; int a[maxn]; int n, k; priority_queue < node > q; signed main() {scanf( "%lld %lld", &n, &k ); n ++;for( int i = 2;i <= n;i ++ ) scanf( "%lld", &a[i] );for( int i = 2;i <= n;i ++ ) a[i] ^= a[i - 1];insert( 0, 1, 0, 1 );for( int i = 2;i <= n;i ++ ) insert( i - 1, i, a[i], i );for( int i = 2;i <= n;i ++ ) {int x = query( root[0], root[i], a[i] );q.push( (node){ 0, i, x, i, a[i] ^ a[x] } );}int ans = 0;while( ! q.empty() and k ) {node now = q.top(); q.pop();k --; ans += now.val; if( now.x - 1 > now.l ) {int x1 = query( root[now.l], root[now.x - 1], a[now.p] );q.push( (node){ now.l, now.x - 1, x1, now.p, a[now.p] ^ a[x1] } );}if( now.x < now.r ) {int x2 = query( root[now.x], root[now.r], a[now.p] );q.push( (node){ now.x, now.r, x2, now.p, a[now.p] ^ a[x2] } );}}printf( "%lld\n", ans );return 0; }總結(jié)
以上是生活随笔為你收集整理的[十二省联考 2019] 异或粽子(可持久化字典树 + 二叉堆)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何开发一套简单的windows软件如何
- 下一篇: [省选联考 2020 A/B 卷] 冰火