P5283 [十二省联考 2019] 异或粽子
P5283 [十二省联考 2019] 异或粽子
[十二省联考 2019] 异或粽子
题目描述
小粽是一个喜欢吃粽子的好孩子。今天她在家里自己做起了粽子。
小粽面前有 \(n\) 种互不相同的粽子馅儿,小粽将它们摆放为了一排,并从左至右编号为 \(1\) 到 \(n\)。第 \(i\) 种馅儿具有一个非负整数的属性值 \(a_i\)。每种馅儿的数量都足够多,即小粽不会因为缺少原料而做不出想要的粽子。小粽准备用这些馅儿来做出 \(k\) 个粽子。
小粽的做法是:选两个整数数 \(l\), \(r\),满足 \(1 \leqslant l \leqslant r \leqslant n\),将编号在 \([l, r]\) 范围内的所有馅儿混合做成一个粽子,所得的粽子的美味度为这些粽子的属性值的异或和。(异或就是我们常说的 xor 运算,即 C/C++ 中的 ˆ
运算符或 Pascal 中的 xor
运算符)
小粽想品尝不同口味的粽子,因此它不希望用同样的馅儿的集合做出一个以上的
粽子。
小粽希望她做出的所有粽子的美味度之和最大。请你帮她求出这个值吧!
输入格式
第一行两个正整数 \(n\), \(k\),表示馅儿的数量,以及小粽打算做出的粽子的数量。
接下来一行为 \(n\) 个非负整数,第 \(i\) 个数为 \(a_i\),表示第 \(i\) 个粽子的属性值。
对于所有的输入数据都满足:\(1 \leqslant n \leqslant 5 \times 10^5\), \(1 \leqslant k \leqslant \min\left\{\frac{n(n-1)}{2},2 \times 10^{5}\right\}\), \(0 \leqslant a_i \leqslant 4 294 967 295\)。
输出格式
输出一行一个整数,表示小粽可以做出的粽子的美味度之和的最大值。
----------------------------------------------------------------------------------
我们用依旧用 0/1Trie 维护粽子馅的xor前缀和
由题目可知:
小粽面前有n种互不相同的粽子馅儿
它不希望用同样的馅儿的集合做出一个以上的粽子
也就是说,我们只需要保证同样的 [l,r] 不会重复出现就好了
不难想到开一个优先队列来维护,每次在 [l,r] 内
用 [pos,r] 做出一个粽子之后,将其拆分为 [l,pos-1] 和 [pos+1,r] 就好了
Code:
#include<bits/stdc++.h>
const int N=5e5+5;
typedef long long ll;
using namespace std;
int n,k,tot;
ll a[N];
int rt[N];
ll ans;
struct Trie{
int ch[2],cnt,id;
}t[N*40];
void ins(int &now,int last,int len,int id,int x)
{
now=++tot;
t[now]=t[last];
t[now].cnt++;
if(len==-1)
{
t[now].id=id;
return ;
}
int bit=(x>>len)&1;
ins(t[now].ch[bit],t[last].ch[bit],len-1,id,x);
}
int find_id(int l,int r,int len,int x)
{
if(len==-1)return t[r].id;
int bit=(x>>len)&1;
if(t[t[l].ch[bit^1]].cnt<t[t[r].ch[bit^1]].cnt)
{
return find_id(t[l].ch[bit^1],t[r].ch[bit^1],len-1,x);
}
else
{
return find_id(t[l].ch[bit],t[r].ch[bit],len-1,x);
}
}
struct Range
{
int l,r,x,id;
ll val;
Range(int _l=0,int _r=0,int _x=0)
{
l=_l,r=_r,x=_x;
id=find_id(rt[l-1],rt[r],31,a[x]);
val=a[x]^a[id-1];
//cout<<"id:"<<l<<" "<<r<<" "<<x<<"=="<<id<<":"<<val<<"\n";
}
bool operator <(const Range &r1)const{
return val<r1.val;
}
};
priority_queue<Range> Q;
void work()
{
cin>>n>>k;
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
a[i]^=a[i-1];
}
for(int i=1;i<=n;i++)
{
rt[i]=rt[i-1];
ins(rt[i],rt[i],31,i,a[i-1]);
}
for(int i=1;i<=n;i++)
{
Q.push(Range(1,i,i));
}
for(int i=1;i<=k;i++)
{
Range tp=Q.top();Q.pop();
int l=tp.l,r=tp.r,id=tp.id,x=tp.x;
ll val=tp.val;
ans+=val;
//cout<<"ans:"<<val<<"--"<<l<<" "<<id<<" "<<r<<"\n";
if(l<=id-1) Q.push(Range(l,id-1,x));
if(id+1<=r) Q.push(Range(id+1,r,x));
}
printf("%lld",ans);
}
int main()
{
freopen("P5283.in","r",stdin);//freopen("P5283.out","w",stdout);
work();
}