P5283 [十二省聯考2019]異或粽子 題解
阿新 • • 發佈:2022-05-20
首先求出原陣列的字首 xor
陣列 \(s\),這樣相當於要在其中找兩個值使其 xor
起來最大。
維護一個堆,裡面有 \(n\) 個元素,分別為當前與 \(s_i\) 異或最大的數。每次取出來一個就把與當前這個 \(s_i\) 異或次大的數放進去,以此類推即可。使用類似線段樹二分的方法可以做到在trie樹上求與某個數異或第 \(k\) 大的數。
要注意,這樣的話每一段會被問到兩次,所以考慮再記一個當前這個 \(s_i\) 與哪個 \(s_j\) 的異或值最大,每次把 \(i,j\) 都向後推。還要注意當 \(s\) 值相同的時候要定好順序。複雜度是 \(O((n+k)\log v)\)
點選檢視程式碼
#include<iostream> #include<cstdio> #include<queue> #include<vector> #define mp std::make_pair #define fi first #define se second typedef long long ll; typedef std::pair<ll,int> pii; inline ll rd(){ ll res=0;char c=getchar(); for(;!isdigit(c);c=getchar()); for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0'); return res; } const int N=5e5+13,M=32+13; const ll INF=0x3f3f3f3f3f3f3f3fll; struct Trie{ int ch[N*M][2],siz[N*M],tot,a[M]; std::vector<int> num[N*M]; Trie(){tot=1;} inline void insert(ll x,int i){ for(int i=0;i<32;++i) a[i]=(x&1),x>>=1; int p=1; for(int i=31;i>=0;--i){ if(!ch[p][a[i]]) ch[p][a[i]]=++tot; p=ch[p][a[i]],++siz[p]; } num[p].push_back(i); } inline pii query(ll x,int k){ for(int i=0;i<32;++i) a[i]=(x&1),x>>=1; int p=1;ll res=0; for(int i=31;i>=0;--i){ if(siz[ch[p][a[i]^1]]>=k) res|=(1ll<<i),p=ch[p][a[i]^1]; else{ k-=siz[ch[p][a[i]^1]]; p=ch[p][a[i]]; } } return mp(res,num[p][k-1]); } }T; struct Node{ ll x;int id1,id2,flag; bool operator <(const Node &a)const{ if(x==a.x) return id2>a.id2; return x<a.x; } }; std::priority_queue<Node> s; int n,m,b[N]; ll a[N]; int main(){ //freopen("2.in","r",stdin); //freopen("P5283.out","w",stdout); n=rd(),m=rd(); for(int i=1;i<=n;++i) a[i]=rd()^a[i-1],T.insert(a[i],i); for(int i=0;i<=n;++i){ pii now=T.query(a[i],b[i]=1); s.push((Node){now.fi,now.se,i,b[i]}); } ll ans=0; while(m--&&!s.empty()){ ll tmp=s.top().x; int i=s.top().id1,j=s.top().id2,flag=s.top().flag;s.pop(); if(flag!=b[j]){++m;continue;} ans+=tmp; b[i]++; if(b[i]<=n){ pii now=T.query(a[i],b[i]); s.push((Node){now.fi,now.se,i,b[i]}); } if(i==j) continue; b[j]++; if(b[j]<=n){ pii now=T.query(a[j],b[j]); s.push((Node){now.fi,now.se,j,b[j]}); } } printf("%lld\n",ans); return 0; }