异或粽子

异或粽子

小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。

小粽面前有 $n$ 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 $1$ 到 $n$。第 $i$ 种馅儿具有一个非负整数的属性值 $a_i$。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 $k$ 个粽子。

小粽的做法是:选两个整数数 $l,r$,满足 $1\le l\le r\le n$,将编号在 $[l,r]$ 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的**异或**和。(异或就是我们常说的 $\mathrm{xor}$ 运算,即 C/C++ 中的 `^` 运算符或 Pascal 中的 `xor` 运算符)

小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的粽子。

小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!


Sol

前缀和完后相当于求两点xor和的前k大。

有一个很好的想法:考虑左端点,先把和这个左端点xor最大的右端点放进堆里,然后每次取堆顶,并接着把次大的放进去。

也就是后面的答案一定会由前面的答案得来。

以后想这种区间问题,可以多从端点的角度考虑问题,固定一个端点,另一个统计,取最大等等。

然后查第k大就可持久化trie实现。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 #include<cmath>
 7 #include<queue>
 8 #define maxn 500005
 9 #define ll long long
10 using namespace std;
11 int n,K,cnt,rt[maxn];
12 ll a[maxn],ans;
13 struct node{
14     int ch[2],sz;
15 }tr[maxn*42];
16 struct no{
17     int x,kth;ll v;
18 };
19 bool operator <(no a,no b){
20     return a.v<b.v;
21 }
22 priority_queue<no>q;
23 int get(int w,ll v){
24     return ((1LL<<w)&v)>0;
25 }
26 void ins(int w,int &k,int la,ll v){
27     if(!k)k=++cnt;
28     if(w<0){
29         tr[k].sz=tr[la].sz+1;return;
30     }
31     int f=get(w,v);
32     ins(w-1,tr[k].ch[f],tr[la].ch[f],v);
33     tr[k].ch[f^1]=tr[la].ch[f^1];
34     tr[k].sz=tr[tr[k].ch[0]].sz+tr[tr[k].ch[1]].sz;
35 }
36 ll ask(int w,int k,int la,ll v,int kth){
37     if(w<0)return 0;
38     int f=get(w,v);
39     int s=tr[tr[k].ch[f^1]].sz-tr[tr[la].ch[f^1]].sz;
40     if(w<=5){
41         //printf("%d %d v=%d Kth=%d s=%d\n",w,k,v,kth,s);
42     }
43     if(s>=kth)return ask(w-1,tr[k].ch[f^1],tr[la].ch[f^1],v,kth)+(1LL<<w);
44     else return ask(w-1,tr[k].ch[f],tr[la].ch[f],v,kth-s);
45 }
46 int main(){
47     cin>>n>>K;
48     ins(31,rt[0],rt[0],0);
49     for(int i=1;i<=n;i++){
50         scanf("%lld",&a[i]);
51         a[i]^=a[i-1];
52         ins(31,rt[i],rt[i-1],a[i]);
53     }
54     for(int i=0;i<=n;i++){
55         no t;t.kth=1;t.x=i;t.v=ask(31,rt[n],rt[i],a[t.x],1);
56         //cout<<t.x<<' '<<t.v<<endl;
57         q.push(t);
58     }int co=0;
59     while(!q.empty()){
60         no t=q.top();q.pop();
61         ans+=t.v;t.v=ask(31,rt[n],rt[t.x],a[t.x],t.kth+1);t.kth++;
62         co++;if(co==K)break;
63         q.push(t);
64     }
65     cout<<ans<<endl;
66     return 0;
67 }
View Code

 

posted @ 2019-04-08 07:27  liankewei123456  阅读(427)  评论(0编辑  收藏  举报