1. 程式人生 > 其它 >P5283 [十二省聯考2019]異或粽子 題解

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;
}