cunzai_zsy0531

关注我

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

题面

首先求出原数组的前缀 xor 数组 \(s\),这样相当于要在其中找两个值使其 xor 起来最大。

维护一个堆,里面有 \(n\) 个元素,分别为当前与 \(s_i\) 异或最大的数。每次取出来一个就把与当前这个 \(s_i\) 异或次大的数放进去,以此类推即可。使用类似线段树二分的方法可以做到在trie树上求与某个数异或第 \(k\) 大的数。

要注意,这样的话每一段会被问到两次,所以考虑再记一个当前这个 \(s_i\) 与哪个 \(s_j\) 的异或值最大,每次把 \(i,j\) 都向后推。还要注意当 \(s\) 值相同的时候要定好顺序。复杂度是 \(O((n+k)\log v)\)

点击查看代码
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#define mp std::make_pair
#define fi first
#define se second
typedef long long ll;
typedef std::pair<ll,int> pii;
inline ll rd(){
	ll res=0;char c=getchar();
	for(;!isdigit(c);c=getchar());
	for(;isdigit(c);c=getchar())res=(res<<1)+(res<<3)+(c-'0');
	return res;
}
const int N=5e5+13,M=32+13;
const ll INF=0x3f3f3f3f3f3f3f3fll;
struct Trie{
	int ch[N*M][2],siz[N*M],tot,a[M];
	std::vector<int> num[N*M];
	Trie(){tot=1;}
	inline void insert(ll x,int i){
		for(int i=0;i<32;++i) a[i]=(x&1),x>>=1;
		int p=1;
		for(int i=31;i>=0;--i){
			if(!ch[p][a[i]]) ch[p][a[i]]=++tot;
			p=ch[p][a[i]],++siz[p];
		}
		num[p].push_back(i);
	}
	inline pii query(ll x,int k){
		for(int i=0;i<32;++i) a[i]=(x&1),x>>=1;
		int p=1;ll res=0;
		for(int i=31;i>=0;--i){
			if(siz[ch[p][a[i]^1]]>=k) res|=(1ll<<i),p=ch[p][a[i]^1];
			else{
				k-=siz[ch[p][a[i]^1]];
				p=ch[p][a[i]];
			}
		}
		return mp(res,num[p][k-1]);
	}
}T;
struct Node{
	ll x;int id1,id2,flag;
	bool operator <(const Node &a)const{
		if(x==a.x) return id2>a.id2;
		return x<a.x;
	}
};
std::priority_queue<Node> s;
int n,m,b[N];
ll a[N];
int main(){
	//freopen("2.in","r",stdin);
	//freopen("P5283.out","w",stdout);
	n=rd(),m=rd();
	for(int i=1;i<=n;++i) a[i]=rd()^a[i-1],T.insert(a[i],i);
	for(int i=0;i<=n;++i){
		pii now=T.query(a[i],b[i]=1);
		s.push((Node){now.fi,now.se,i,b[i]});
	}
	ll ans=0;
	while(m--&&!s.empty()){
		ll tmp=s.top().x;
		int i=s.top().id1,j=s.top().id2,flag=s.top().flag;s.pop();
		if(flag!=b[j]){++m;continue;}
		ans+=tmp;
		b[i]++;
		if(b[i]<=n){
			pii now=T.query(a[i],b[i]);
			s.push((Node){now.fi,now.se,i,b[i]});
		}
		if(i==j) continue;
		b[j]++;
		if(b[j]<=n){
			pii now=T.query(a[j],b[j]);
			s.push((Node){now.fi,now.se,j,b[j]});
		}
	}
	printf("%lld\n",ans);
	return 0;
}
posted @ 2022-05-20 12:02  cunzai_zsy0531  阅读(42)  评论(0编辑  收藏  举报