1. 程式人生 > >「十二省聯考 2019」異或粽子——tire樹+堆

「十二省聯考 2019」異或粽子——tire樹+堆

bit clas through 相同 nbsp 在家 然而 div closed

題目

【題目描述】

小粽是一個喜歡吃粽子的好孩子。今天她在家裏自己做起了粽子。

小粽面前有 $n$ 種互不相同的粽子餡兒,小粽將它們擺放為了一排,並從左至右編號為 $1$ 到 $n$。第 $i$ 種餡兒具有一個非負整數的屬性值 $a_i$。每種餡兒的數量都足夠多,即小粽不會因為缺少原料而做不出想要的粽子。小粽準備用這些餡兒來做出 $k$ 個粽子。

小粽的做法是:選兩個整數數 $l,r$,滿足 $1\le l\le r\le n$,將編號在 $[l,r]$ 範圍內的所有餡兒混合做成一個粽子,所得的粽子的美味度為這些粽子的屬性值的**異或**和。(異或就是我們常說的 $\mathrm{xor}$ 運算,即 C/C++ 中的 `^` 運算符或 Pascal 中的 `xor` 運算符)

小粽想品嘗不同口味的粽子,因此它不希望用同樣的餡兒的集合做出一個以上的粽子。

小粽希望她做出的所有粽子的美味度之和最大。請你幫她求出這個值吧!

【輸入格式】

從標準輸入讀入數據。

第一行兩個正整數 $n,k$,表示餡兒的數量,以及小粽打算做出的粽子的數量。

接下來一行為 $n$ 個非負整數,第 $i$ 個數為 $a_i$,表示第 $i$ 個粽子的屬性值。

【輸出格式】

輸出到標準輸出。

輸出一行一個整數,表示小粽可以做出的粽子的美味度之和的最大值。

【樣例輸入】

3 2
1 2 3

【樣例輸出】

6

【數據範圍與提示】

|測試點|$n$|$k$|
|:-:|:-:|:-:|

|$1\sim 8$|$\le 10^{3}$|$\le 10^{3}$|
|$9\sim 12$|$\le 5 \times 10^{5}$|$\le 10^{3}$|
|$13\sim 16$|$\le 10^{3}$|$\le 2 \times 10^{5}$|
|$17\sim 20$|$\le 5 \times 10^{5}$|$\le 2 \times 10^{5}$|


對於所有的輸入數據都滿足:$1\le n \le 5 \times 10^{5},1\le k\le \min\left\{\frac{n(n-1)}{2},2 \times 10^{5}\right\},0\le a_i \le 4,294,967,295$。

題解

首先考慮在前綴異或和上暴力,$ n^2 $ 找出所有的值,放進堆裏,取前 $ k $ 大的即可,效率 $ O(n^2+\log k) $,可以過 $ 60 \% $

顯然把 $ x $ 所有能匹配的都找出來是不可能的,於是考慮在 tire 樹上貪心

建 $ n $ 棵可持久化 tire 樹,然後在 $ [0,i-1] $ 上貪心即可

考慮如何去重

於是我在測試時想到將 $ x $ 貪心對應的最大值的點 $ p $ 挖掉,然後變成兩個區間 $ [l,p-1] $ 和 $ [p+1,r] $,找對應點時建一個鏈表即可(類似《超級鋼琴》)

然而這樣的常數太大,於是 map TLE,但還有 unorder map 嘛,跑得飛快

其實可以在 tire 樹上二分第 $ k $ 大的值,放入堆時記錄下是第 $ k $ 大的即可,為什麽我沒有想到

代碼

顯然二分是不可能去寫的

技術分享圖片
 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 #define U unsigned
 4 #include<tr1/unordered_map>
 5 #define _(d) while(d(isdigit(ch=getchar())))
 6 using namespace std;
 7 LL R(){
 8     LL x;bool f=1;char ch;_(!)if(ch==-)f=0;x=ch^48;
 9     _()x=(x<<3)+(x<<1)+(ch^48);return f?x:-x;}
10 const int N=5e5+5;
11 int n,m,rot[N],tr[N*100][2],cnt,s[N*100][2],nex[N];
12 LL a[N],sum[N],ans;
13 struct node{
14     LL w,v;int l,r;
15     bool friend operator <(node a,node b){return a.w<b.w;}
16 };priority_queue<node> q;
17 tr1::unordered_map<LL,int>mp;
18 void insert(int &k,int o,LL len,LL v){
19     if(!~len)return;
20     k=++cnt;
21     int f=(v>>len)&1;
22     tr[k][f^1]=tr[o][f^1],s[k][f^1]=s[o][f^1],s[k][f]=s[o][f]+1;
23     insert(tr[k][f],tr[o][f],len-1,v);
24 }
25 LL query(int k,int o,LL len,LL v){
26     if(!~len)return 0;
27     int f=(v>>len)&1;
28     if(s[k][f^1]-s[o][f^1])
29         return (1ll<<len)+query(tr[k][f^1],tr[o][f^1],len-1,v);
30     else return query(tr[k][f],tr[o][f],len-1,v);
31 }
32 int find(LL x,int l,int r){
33     for(int k=mp[x];k;k=nex[k])
34         if(k<=r&&k>=l)return k;
35     return 0;}
36 int main(){
37     n=R(),m=R();
38     insert(rot[0],0,32,0);
39     for(int i=1;i<=n;i++){
40         a[i]=R(),sum[i]=sum[i-1]^a[i];
41         nex[i]=mp[sum[i]],mp[sum[i]]=i;
42         insert(rot[i],rot[i-1],32,sum[i]);
43     }
44     for(int i=1;i<=n;i++){
45         LL w=query(rot[i-1],0,32,sum[i]);
46         q.push((node){w,sum[i],0,i-1});
47     }
48     while(m--){
49         node now=q.top();q.pop();ans+=now.w;
50         int id=find(now.w^now.v,now.l,now.r);
51         if(id-1>=now.l)q.push((node){query(rot[id-1],rot[now.l-1],32,now.v),now.v,now.l,id-1});
52         if(now.r>=id+1)q.push((node){query(rot[now.r],rot[id+1-1],32,now.v),now.v,id+1,now.r});
53     }
54     cout<<ans<<endl;
55     return 0;
56 }
View Code

「十二省聯考 2019」異或粽子——tire樹+堆