题意
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有n种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为1到n。第i种馅儿具有一个非负整数的属性值ai 。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出k个粽子。
小粽的做法是:选两个整数数l,r
,满足1<=l<=r<=n,将编号在[l,r]范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的
运算,即 C/C++ 中的 ^
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
输入格式:
第一行两个正整数 n, k,表示馅儿的数量,以及小粽打算做出的粽子的数量。
接下来一行为 n 个非负整数,第 i 个数为 ai,表示第 i 个粽子的属性值。 对于所有的输入数据都满足:1⩽n⩽5×1e5, 1⩽k⩽min{ n(n−1)2, 2×1e5}, 0⩽ai⩽42949672950。
输出格式:
输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。
内存限制:1024 MB 时间限制:2000 ms
题解:
由异或自为逆运算的性质,求出异或前缀和 l~r异或和为a[r]^a[l-1]
这样问题就转化为 求a[0]=0, a[0]~a[n] 中任意两数前k大异或和之和
类似于超级钢琴
做法一
我们先固定右端点 r,然后在 [0,r−1]查一个数异或 sumr 最大。这个可以用可持久化 01trie 实现。
我们将 n个数放入堆中,每次取出最大的那个状态。设这个状态左端点在 [l,r],与 sumx异或起来最大的位置在 k,那么我们把状态的左端点分割成[l,k-1]和 [k+1,r]后放入堆中。
时间复杂度 O(nlogn)。
做法二
注意到这是一个关于三角(ai xor aj,0≤i≤j≤n)的求值,并且有ai xor aj=aj xor ai所以我们先把答案乘二然后再除回去,这样我们要求的就是最大的2k个有序对,这个就很好处理了.对角线上的元素并不影响,因为ai xor ai=0是最小的.
可以对每一个i求出第t(初始为1)大的ai xor aj,然后把结果扔到堆里,每次取堆顶,然后把堆顶对应的i的第t+1大的ai xor aj扔进堆里.
做法一代码 注意可持久化trie的边界问题 因为可能要查找区间[0,r],实际上rt[-1]=0 注意特判
1 #include<cstdio> 2 #include<queue> 3 using namespace std; 4 const int N=5*1e5+15; 5 int n,k; long long a[N],ans; 6 7 struct point{int l,r,pos; long long he,val;}; 8 inline bool operator <(const point a,const point b) {return a.val<b.val;} 9 priority_queue<point> q; 10 11 int rt[N],cnt; 12 struct tree{int ch[2],pos,sum;}t[N*40]; 13 inline void insert(int& now,int las,int pos,long long x) 14 {if(las<0) las=0; else las=rt[las]; 15 16 now=++cnt; int tmp=now; 17 for(int i=31;i>=0;i--) 18 {t[tmp]=t[las]; t[tmp].sum++; 19 long long cmp=((x>>i)&1); 20 tmp=t[tmp].ch[cmp]=++cnt; las=t[las].ch[cmp]; 21 } 22 t[tmp]=t[las]; t[tmp].sum++; t[tmp].pos=pos; 23 } 24 25 inline int ask(int l,int r,long long x) 26 { 27 if(l==-1) l=0; else l=rt[l]; 28 29 for(int i=31;i>=0;i--) 30 {long long cmp=((x>>i)&1); 31 if(t[t[r].ch[cmp^1]].sum>t[t[l].ch[cmp^1]].sum) 32 {l=t[l].ch[cmp^1],r=t[r].ch[cmp^1];} 33 else 34 {l=t[l].ch[cmp],r=t[r].ch[cmp];} 35 } 36 return t[r].pos; 37 } 38 39 inline long long read() 40 {long long re=0; char ch=getchar(); 41 while(!('0'<= ch && ch<='9')) ch=getchar(); 42 while('0'<= ch && ch<='9') {re=re*10+ch-'0'; ch=getchar();} 43 return re; 44 } 45 int main() 46 { 47 n=read(); k=read(); 48 for(int i=1;i<=n;i++) a[i]=(read()^a[i-1]); 49 50 for(int i=0;i<=n;i++) {insert(rt[i],i-1,i,a[i]);} 51 52 for(int i=1;i<=n;i++) 53 {point s; 54 s.l=0; s.r=i-1; s.he=a[i]; 55 s.pos=ask(s.l-1,rt[s.r],s.he); 56 s.val=(s.he^a[s.pos]); 57 q.push(s); 58 } 59 60 while(k--) 61 {point s,x=q.top(); q.pop(); ans+=x.val; 62 63 s.l=x.l; s.r=x.pos-1; s.he=x.he; 64 if(s.l<=s.r) 65 { s.pos=ask(s.l-1,rt[s.r],s.he); 66 s.val=(s.he^a[s.pos]); 67 q.push(s); 68 } 69 70 s.l=x.pos+1; s.r=x.r; s.he=x.he; 71 if(s.l<=s.r) 72 { s.pos=ask(s.l-1,rt[s.r],s.he); 73 s.val=(s.he^a[s.pos]); 74 q.push(s); 75 } 76 } 77 printf("%lld",ans); 78 79 return 0; 80 }