题解:CF1983F array-value
yingkeqian9217 · · 题解
这里提供一种比较好写的时间复杂度
套路地,对于求第
注意到
0 的限制是平凡的,只需要这几位都取相同即可;对于 1 的限制,注意到这一位的取 0 或 1 均无关,所以等价于无限制。此时我们只要对于拆成的每个贡献计算只保留元素对应 0 位的二进制值即可,此时问题等价于求等值前驱,容易维护。此时时间复杂度
考虑在二进制问题中二分答案的另一种表现形式,拆位贪心。当我们从高到低逐位考虑时,每次只会加入 1 条限制,直接在匹配数组上取最大值即可,单次只需要扫一次数组。
用哈希表实现前驱,时间复杂度
#include<bits/stdc++.h>
#define maxn 510005
#define int long long
using namespace std;
int n,k,a[maxn],pre[maxn];
unordered_map<int,int>mp;
int check(int x){
mp.clear();
int res=0,maxx=0;
for(int i=1;i<=n;i++){
int cur=a[i]&x;
maxx=max(maxx,pre[i]);
if(mp.count(cur)) maxx=max(maxx,mp[cur]);
mp[cur]=i;
res+=maxx;
if(res>=k) return 0;
}
return 1;
}
void update(int x){
mp.clear();
for(int i=1;i<=n;i++){
int cur=a[i]&x;
pre[i]=max(pre[i],pre[i-1]);
if(mp.count(cur)) pre[i]=max(pre[i],mp[cur]);
mp[cur]=i;
}
}
void solve(){
int x=0;
scanf("%lld%lld",&n,&k);
for(int i=1;i<=n;i++) scanf("%lld",&a[i]),pre[i]=0;
for(int i=30;i>=0;i--){
if(check(~(x|((1<<i)-1)))) update(~(x|((1<<i)-1))),x|=(1<<i);
}
printf("%lld\n",x);
}
signed main(){
signed T=1;
scanf("%d",&T);
while(T--) solve();
return 0;
}