[十二省联考 2019][堆][可持久化trie树]异或粽子

题意

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

小粽面前有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

输出格式:

扫描二维码关注公众号,回复: 5851754 查看本文章

输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。

内存限制: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(nlog⁡n)

做法二

注意到这是一个关于三角(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 }

猜你喜欢

转载自www.cnblogs.com/YuXiaoze/p/10692176.html