题解:CF2026E Best Subsequence

· · 题解

前言

什么最小割、最大权闭合子图之类的,我不知道啊。就是二分图的最大独立集呀。

思路

先考虑每一个数。
数与数之间互不干扰,数位与数位之间也互不影响。只有数与数位会互相影响。二分图?

建一张二分图,左侧为 n 个数,右侧为 60 个二进制位。考虑连边。如果一个数 a_i 二进制下的第 j 位数为 1,会产生负贡献,那就连边。

显然,这是一个最大独立集问题,跑一遍匹配即可。因为每一个点仅会与另外一个点匹配。根据按位或的性质,如果两个数相同二进制位上的数都是 1,它还是 1,和二分图匹配的特点正好相同。因此没有问题。

代码

#include<iostream>
#include<cstring>
using namespace std;
int t,n;
const int N=1e5+10;
long long a[N];
int h[N],e[N],ne[N],idx;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
int match[N];
bool st[110];
bool find(int x){
    for(int i=h[x];i!=-1;i=ne[i]){
        int j=e[i];
        if(!st[j]){
            st[j]=true;
            if(match[j]==0||find(match[j])){
                match[j]=x;
                return true;
            }
        }
    }
    return false;
}
int main(){
    cin>>t;
    while(t--){
        scanf("%d",&n);
        idx=0;
        for(int i=1;i<=100;i++){
            h[i]=-1,match[i]=0;
        }
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i]);
            for(int j=0;j<=60;j++){
                if(a[i]>>j&1){
                    add(i,j+1);
                }
            }
        }
        int ans=0;
        for(int i=1;i<=n;i++){
            memset(st,0,sizeof st);
            ans+=find(i);
        }
        cout<<n-ans<<endl;
    }
}