第 k 大区间

题目链接:第 k 大区间


因为k很大,显然可以想到二分。利用前缀异或和变成两个点的异或。然后就是枚举每一个后缀,求异或大于某个数的个数。

直接Trie上查询即可。


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e5+10;
int n,k,a[N],ch[N*32][2],sz[N*32],idx;
inline void insert(int x){
	int p=0;
	for(int i=30;i>=0;i--){
		int k=x>>i&1;
		if(!ch[p][k]) ch[p][k]=++idx;
		p=ch[p][k]; sz[p]++;
	}
}
inline int ask(int x,int mid){
	int p=0,s=0,cnt=0;
	for(int i=30;i>=0;i--){
		int k=x>>i&1;
		if(s+(1<<i)>=mid) cnt+=sz[ch[p][k^1]],p=ch[p][k];
		else s+=(1<<i),p=ch[p][k^1];
		if(!p) return cnt;
	}
	return cnt;
}
inline int check(int mid){
	int sum=0,s=0;
	memset(ch,0,sizeof ch),memset(sz,0,sizeof sz),idx=0;
	insert(0);
	for(int i=1;i<=n;i++){
		s^=a[i],sum+=ask(s,mid);
		insert(s);
	}
	return sum>=k;
}
signed main(){
	cin>>n>>k;
	for(int i=1;i<=n;i++) cin>>a[i];
	int l=0,r=4e9;
	while(l<r){
		int mid=l+r+1>>1;
		if(check(mid)) l=mid;
		else r=mid-1;
	}
	cout<<l;
	return 0;
}
已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页