题目
t(t<=2e4)组样例,每次给定长度n(n<=1e5)序列a(0<=ai<=1e9)
对于长度>=2的区间[l,r],定义b[l,r]为区间[l,r]内ai异或aj(l<=i<j<=r)的最小值,
求整个数组b值的第k小,即从小到大第k个的值
思路来源
难题肉搏小组
题解
先把第k小转成第k大,
然后二分答案mid,求有多少区间[l,r]满足b值>=mid
对于(a[i]^a[j])>=mid,即不存在(a[i]^x)<mid的x,
枚举右端点,对于右端点r来说,已经得到了左端点l,
那么r+1对应的左端点只会在l右侧,具有单调性,
所以把r+1对应的值a[r+1]加入到trie树前,
先检查trie上是否有值违背规则,即(a[r+1]^x)<mid,
双指针单增,把这样的x从trie上删掉,得到新的l’,
遍历所有右端点即得到合法区间数,
满足数量则往大里二分,否则往小里二分
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
#include<set>
using namespace std;
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
typedef long long ll;
typedef double db;
typedef pair<int,int> P;
#define fi first
#define se second
#define pb push_back
#define dbg(x) cerr<<(#x)<<":"<<x<<" ";
#define dbg2(x) cerr<<(#x)<<":"<<x<<endl;
#define SZ(a) (int)(a.size())
#define sci(a) scanf("%d",&(a))
#define pt(a) printf("%d",a);
#define pte(a) printf("%d\n",a)
#define ptlle(a) printf("%lld\n",a)
#define debug(...) fprintf(stderr, __VA_ARGS__)
using namespace std;
const int N=1e5+10,M=3e6+10;
int t,n,a[N];
ll k;
int tr[M][2],cnt,num[M];
void init(){
cnt=0;
memset(tr[0],0,sizeof tr[0]);
num[0]=0;
}
void add(int x){
int rt=0;
for(int i=30;i>=0;--i){
int v=x>>i&1;
if(!tr[rt][v]){
tr[rt][v]=++cnt;
num[cnt]=0;
memset(tr[cnt],0,sizeof tr[cnt]);
}
rt=tr[rt][v];
num[rt]++;
}
}
void del(int x){
int rt=0;
for(int i=30;i>=0;--i){
int v=x>>i&1;
rt=tr[rt][v];
num[rt]--;
}
}
bool ok(int mid){//(a[i]^a[j])>=mid 即不存在(a[i]^x)<mid的x 单调性 双指针
ll ans=0;
init();
int now=1;
rep(i,1,n){
int rt=0;
for(int j=30;j>=0;--j){
int v=a[i]>>j&1,w=mid>>j&1,x=v^w;
if(w==1){//0^0<1 1^1<1
while(now<i && tr[rt][v] && num[tr[rt][v]]>0){
del(a[now++]);
}
}
if(!tr[rt][x])break;
rt=tr[rt][x];
}
ans+=i-now;
//printf("mid:%d i:%d now:%d ans:%lld\n",mid,i,now,ans);
add(a[i]);
if(ans>=k)return 1;
}
return 0;
}
int main(){
sci(t);
while(t--){
scanf("%d%lld",&n,&k);
k=1ll*n*(n-1)/2-k+1;
rep(i,1,n)sci(a[i]);
int l=0,r=(1<<30)-1;
while(l<=r){
int mid=l+(r-l)/2;
if(ok(mid))l=mid+1;
else r=mid-1;
}
pte(r);
}
return 0;
}