题意
内存限制:1024 MiB
时间限制:1500 ms
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 nnn 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 111 到 nnn。第 iii 种馅儿具有一个非负整数的属性值 aia_iai。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 kkk 个粽子。
小粽的做法是:选两个整数数 l,rl,rl,r,满足 1≤l≤r≤n1\le l\le r\le n1≤l≤r≤n,将编号在 [l,r][l,r][l,r] 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 xor\mathrm{xor}xor 运算,即 C/C++ 中的 ^
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
1≤n≤5×105,1≤k≤min{n(n−1)2,2×105},0≤ai≤4,294,967,2951\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,2951≤n≤5×105,1≤k≤min{2n(n−1),2×105},0≤ai≤4,294,967,295
题解
把 aia_iai 变成前缀异或和,所以实际上是在 [0,n][0,n][0,n] 中选 kkk 对 (x,y)(x,y)(x,y) 使 ∑ax⊕ay\sum a_x \oplus a_y∑ax⊕ay 最大
考虑到 kkk 不是很大,我们可以建立堆,一开始把每个数选到最大的数丢到堆中,然后以异或值作为关键字排序,每次取出堆顶,然后找其第二大异或值丢到堆中……
所以可以发现我们需要查询对于 iii , j∈[0,i−1]j \in [0,i-1]j∈[0,i−1] 的 ai⊕aja_i \oplus a_jai⊕aj 第 kkk 大数是多少
所以可以建立可持久化 trietrietrie 树,在 trietrietrie 树上进行二分即可
#include <bits/stdc++.h>
#define I inline
#define LL long long
using namespace std;
const int N=5e5+5;
int n,K,T[N],tt;LL a[N],ans;
struct O{int s,ch[2];}t[N<<6];
struct Q{
int x,k;LL v;
I friend bool operator < (const Q& A,const Q& B){
return A.v<B.v;
}
};priority_queue<Q>q;
I void ins(int& x,LL v,int d){
t[++tt]=t[x];x=tt;t[x].s++;
if (~d) ins(t[x].ch[(v>>d)&1ll],v,d-1);
}
I LL query(int x,LL y,int k,int d){
if (!~d) return 0;
bool v=(y>>d)&1ll;
int s=t[t[x].ch[v^1]].s;
if (k<=s) return query(t[x].ch[v^1],y,k,d-1)|(1ll<<d);
return query(t[x].ch[v],y,k-s,d-1);
}
int main(){
scanf("%d%d",&n,&K);
for (int i=1;i<=n;i++)
scanf("%lld",&a[i]),a[i]^=a[i-1],
ins(T[i]=T[i-1],a[i-1],31),
q.push((Q){i,1,query(T[i],a[i],1,31)});
for (int i=1;i<=K;i++){
Q y=q.top();q.pop();ans+=y.v;
if (y.k<=y.x) q.push((Q){y.x,y.k+1,query(T[y.x],a[y.x],y.k+1,31)});
}
return printf("%lld\n",ans),0;
}