题意:
求前k大连续子段异或和
1. 做前缀异或和,然后变成求最大的k对异或和的和
2. 可以对每一个i求出第t(初始为1)大的$a_i xor a_j$,然后把结果扔到堆里,每次取堆顶,然后把堆顶对应的i的第t+1大的$a_i xor a_j$扔进堆里
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<vector> #include<queue> using namespace std; #define re register #define ll long long #define gc getchar() inline ll read() { re ll x(0);re char c(gc); while(c>'9'||c<'0') c=gc; while(c>='0'&&c<='9')x=x*10+c-48,c=gc; return x; } const int N=2e7+10; ll n,k,a[N][2],siz[N],m,tot; ll ans=1,x,s[N]; struct node {int id,rk;ll w;}; bool operator < (node a,node b){return a.w<b.w;} priority_queue<node> q; void ins(ll x) { int u=0; for(int i=31;i>=0;--i) { int ch=(x>>i)&1;siz[u]++; if(!a[u][ch]) a[u][ch]=++tot; u=a[u][ch]; } siz[u]++; } ll query(ll x,int rk) { int u=0;ll an=0; for(int i=31;i>=0;--i) { int ch=(x>>i)&1; if(!a[u][ch^1]) u=a[u][ch]; else if(rk<=siz[a[u][ch^1]]) u=a[u][ch^1],an|=1LL<<i; else rk-=siz[a[u][ch^1]],u=a[u][ch]; } return an; } int main() { n=read(),k=read(),k<<=1; for(int i=1;i<=n;++i) x=read(),s[i]=s[i-1]^x; for(int i=0;i<=n;++i) ins(s[i]); for(int i=0;i<=n;++i) q.push((node){i,1,query(s[i],1)}); for(int i=1;i<=k;++i) { node u=q.top(); ans+=u.w;q.pop(); if(u.rk<n) q.push((node){u.id,u.rk+1,query(s[u.id],u.rk+1)}); } cout<<(ans>>1)<<endl; return 0; }