码迷,mamicode.com
首页 > 其他好文 > 详细

[loj3048]异或粽子

时间:2020-03-26 21:34:50      阅读:61      评论:0      收藏:0      [点我收藏+]

标签:lap   无法   全局   ++   spl   --   fir   printf   namespace   

先对其求出前缀异或和,然后$o(k)$次枚举,每次选择最大值,考虑如何维护
可以全局开一个堆,维护出每一个点的最大值的最大值,那么相当于要在一个点中删去一个点再找到最大值
将这些删去的点重新建成一颗trie树,与所有数构成的trie树减一下,就可以找到新的最大值了,再用堆维护即可
有一些细节:1.数值范围较大,需要开long long;2.由于无法判断位置关系,因此要取2k个并将答案除以2

技术图片
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 500005
 4 #define ll long long
 5 set<pair<ll,int> >s;
 6 int V,n,m,ch[N*70][2],sz[N*70];
 7 ll ans,a[N];
 8 void add(int k,ll x){
 9     sz[k]++;
10     for(int i=31;i>=0;i--){
11         int p=((((1LL<<i)&x)>0));
12         if (!ch[k][p])ch[k][p]=++V;
13         k=ch[k][p];
14         sz[k]++;
15     }
16 }
17 ll query(int k1,int k2,ll x){
18     ll ans=0;
19     for(int i=31;i>=0;i--){
20         int p=(((1LL<<i)&x)==0);
21         if (sz[ch[k1][p]]==sz[ch[k2][p]])p^=1;
22         ans+=p*(1LL<<i);
23         k1=ch[k1][p];
24         k2=ch[k2][p];
25     }
26     return ans;
27 }
28 int main(){
29     scanf("%d%d",&n,&m);
30     for(int i=1;i<=n;i++){
31         scanf("%lld",&a[i]);
32         a[i]^=a[i-1];
33     }
34     V=n+2;
35     for(int i=0;i<=n;i++)add(1,a[i]);
36     for(int i=0;i<=n;i++)s.insert(make_pair(-(a[i]^query(1,i+2,a[i])),i));
37     m*=2;
38     for(int i=1;i<=m;i++){
39         ans-=(*s.begin()).first;
40         int k=(*s.begin()).second;
41         s.erase(s.begin());
42         add(k+2,query(1,k+2,a[k]));
43         s.insert(make_pair(-(a[k]^query(1,k+2,a[k])),k));
44     }
45     printf("%lld",ans/2);
46 } 
View Code

 

[loj3048]异或粽子

标签:lap   无法   全局   ++   spl   --   fir   printf   namespace   

原文地址:https://www.cnblogs.com/PYWBKTDA/p/12577286.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!