P5283 [十二省联考 2019] 异或粽子

P5283 [十二省联考 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]
[x,r] 做出一个粽子之后,将其拆分为 [l,x-1][x+1,r] 就好了。

感觉当年写的好简单,现在来补一些东西:

首先,我们维护一颗可持久化 0/1trie 用来维护当前区间 \([l,r]\) 内的最大异或和。 \(O(\log n)\) 插入,\(O(\log n)\) 查询。然后对于选区间 :我们先钦定一个确定的右端点 \(R\) 。我们初始时将所有区间 \([1,R] \ R\in [1,n]\) 插入到一个优先队列中,优先队列维护一下变量:\(l,r,x,R\) 分别表示当前左端点可选择的区间 \([l,r]\),当前钦定的右端点 \(R\),在区间 \(x\in [l,r]\) 上能取到的能使得 \([x,R]\) 的异或和最大的点 \(x\)。然后我们每一次将 \([x,R]\) 这段区间取用后,剩下的区间就会被分成 \(x_1\in[l,x-1] \ \ [x_1,R] \ ;\ x_2\in[x+1,r] \ [x_2,R]\) 两段。这样就保证了 \([x,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,x;
}t[N*40];
#define bit ((R>>len)&1)
void ins(int &now,int last,int len,int x,int R)
{
	t[now=++tot]=t[last];t[now].cnt++;
	if(len==-1){t[now].x=x;return ;}
	ins(t[now].ch[bit],t[last].ch[bit],len-1,x,R);
}
int find_x(int l,int r,int len,int R)
{
	if(len==-1)return t[r].x;
	if(t[t[l].ch[bit^1]].cnt<t[t[r].ch[bit^1]].cnt){return find_x(t[l].ch[bit^1],t[r].ch[bit^1],len-1,R);}
	else {return find_x(t[l].ch[bit],t[r].ch[bit],len-1,R);}
}
struct Range
{
	int l,r,R,x;
	ll val;
	Range(int _l=0,int _r=0,int _R=0)
	{
		l=_l,r=_r,R=_R;
		x=find_x(rt[l-1],rt[r],31,a[R]);
		val=a[R]^a[x-1];
	}
	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++){ins(rt[i],rt[i-1],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,x=tp.x,R=tp.R;
        ans+=tp.val;
		if(l<=x-1) Q.push(Range(l,x-1,R));
		if(x+1<=r) Q.push(Range(x+1,r,R));
	}
	printf("%lld",ans);
}
int main()
{
	//freopen("P5283.in","r",stdin);//freopen("P5283.out","w",stdout);
	work();
}
posted @ 2024-12-06 11:43  liuboom  阅读(49)  评论(0)    收藏  举报