异或粽子
异或粽子
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 $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 }