P5283 異或粽子
阿新 • • 發佈:2020-10-14
https://www.luogu.com.cn/problem/P5283
其實並不需要可持久化,只需要不同的 trie 就行了
先把它來個異或字首和,這樣問題就轉化為了求前 \(k\) 大的任意兩數異或的和,記得要補一個 \(0\)
因為異或有交換律,不妨先求前 \(2k\) 大的和,然後答案除以二,這樣就不用考慮重複的問題了
然後把每個數插入到 trie 上,這樣可以 \(O(\log a_i)\) 的求一個數與這個數列中其他數異或的第 \(rank\) 大的結果(考慮每一位是向和這個數在那一位相同的數字方向走,還是相異)
然後開一個堆,首先把每個數和別的數異或的最大結果插入堆中,然後每次取出最大值,假設這是某個數與其他數異或的第 \(rk\)
另外手寫對跑的真比 stl 的快得多,在不開O2的程式碼中大概第三左右
#include<cstdio> #include<algorithm> #include<iostream> #include<cmath> #include<map> #include<iomanip> #include<cstring> #define reg register #define EN puts("") inline long long read(){ register long long x=0;register int y=1; register char c=std::getchar(); while(c<'0'||c>'9'){if(c=='-') y=0;c=std::getchar();} while(c>='0'&&c<='9'){x=x*10+(c^48);c=std::getchar();} return y?x:-x; } int n,k; struct node{ int id,rk; long long num; }heap[50000006]; int size; struct tr{ tr *son[2]; int cnt; }dizhi[50000006],*root,*null; int tot; long long a[500006]; inline void New(tr *&a){ a=&dizhi[++tot]; a->son[0]=a->son[1]=null; } #define MAX 33 void insert(tr *tree,long long num,int pos){ tree->cnt++; if(pos<0) return; int nex=(num>>pos)&1; if(tree->son[nex]==null) New(tree->son[nex]); insert(tree->son[nex],num,pos-1); } long long ask(tr *tree,long long num,int rk,int pos){ // printf("rk = %d\n",rk); if(pos<0) return 0; int nex=((num>>pos)&1)^1; if(tree->son[nex]->cnt>=rk) return (1ll<<pos)+ask(tree->son[nex],num,rk,pos-1); return ask(tree->son[nex^1],num,rk-tree->son[nex]->cnt,pos-1); } inline int operator >=(const node &a,const node &b){return a.num>=b.num;} inline void push(node x){ heap[++size]=x; reg int i=size,fa; while(i>1){ fa=i>>1; if(heap[fa]>=heap[i]) return; std::swap(heap[fa],heap[i]);i=fa; } } inline node pop(){ node ret=heap[1];heap[1]=heap[size--]; reg int i=1,ls,rs; while((i<<1)<=size){ ls=i<<1;rs=ls|1; if(rs<=size&&heap[rs]>=heap[ls]) ls=rs; if(heap[i]>=heap[ls]) break; std::swap(heap[i],heap[ls]);i=ls; } return ret; } int main(){ n=read();k=read()*2; null=&dizhi[0];null->son[0]=null->son[1]=null; New(root); insert(root,0,MAX); for(reg int i=1;i<=n;i++){ a[i]=read()^a[i-1]; insert(root,a[i],MAX); } for(reg int i=0;i<=n;i++) push((node){i,1,ask(root,a[i],1,MAX)}); reg node now;long long ans=0; while(k--){ now=pop(); ans+=now.num; if(now.rk<n) push((node){now.id,now.rk+1,ask(root,a[now.id],now.rk+1,MAX)}); } printf("%lld",ans>>1); return 0; }