题目描述
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 nn 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 11 到 nn。第 ii 种馅儿具有一个非负整数的属性值 a_iai。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 kk 个粽子。
小粽的做法是:选两个整数数 ll, rr,满足 1 leqslant l leqslant r leqslant n1⩽l⩽r⩽n,将编号在 [l, r][l,r] 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 xor 运算,即 C/C++ 中的 ˆ
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的 粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
输入输出格式
输入格式:
第一行两个正整数 nn, kk,表示馅儿的数量,以及小粽打算做出的粽子的数量。
接下来一行为 nn 个非负整数,第 ii 个数为 a_iai,表示第 ii 个粽子的属性值。 对于所有的输入数据都满足:1 leqslant n leqslant 5 imes 10^51⩽n⩽5×105, 1 leqslant k leqslant minleft{frac{n(n-1)}{2},2 imes 10^{5} ight}1⩽k⩽min{2n(n−1),2×105}, 0 leqslant a_i leqslant 4 294 967 2950⩽ai⩽4294967295。
输出格式:
输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。
输入输出样例
题解
-
把前缀和扔进Trie里面,用一个堆维护每个位置当前的最大贡献,每次贪心取然后更改
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 #include <queue> 5 #define ll long long 6 using namespace std; 7 const ll N=500010,M=N*32; 8 struct node 9 { 10 ll id,val; 11 bool operator <(const node &o)const { return val<o.val; } 12 }; 13 priority_queue<node> Q; 14 ll n,k,tot,ans,now[N],ch[M][2],sz[M],cnt[M],s[N]; 15 void insert(ll x) 16 { 17 ll r=0; 18 for (ll i=31,c;~i;i--) 19 { 20 c=(x&(1ll<<i))?1:0; 21 if (!ch[r][c]) ch[r][c]=++tot; 22 ++sz[r=ch[r][c]]; 23 } 24 ++cnt[r]; 25 } 26 ll kth(ll x,ll k) 27 { 28 ll r=0; ll R=0; 29 for (ll i=31,c;~i;i--) 30 { 31 c=(x&(1ll<<i))?0:1; 32 if (sz[ch[r][c]]<k) k-=sz[ch[r][c]],r=ch[r][!c]; else R^=1ll<<i,r=ch[r][c]; 33 } 34 return R; 35 } 36 int main() 37 { 38 scanf("%lld%lld",&n,&k),k<<=1,insert(0); 39 for (ll i=1,x;i<=n;i++) scanf("%lld",&x),s[i]=s[i-1]^x,insert(s[i]); 40 for (ll i=0;i<=n;i++) Q.push(node{i,kth(s[i],++now[i])}); 41 while (k--) 42 { 43 node u=Q.top(); Q.pop(); 44 if (k&1) ans+=u.val; 45 if (now[u.id]<n) Q.push(node{u.id,kth(s[u.id],++now[u.id])}); 46 } 47 printf("%lld",ans); 48 }