专栏文章

题解:CF2026E Best Subsequence

CF2026E题解参与者 1已保存评论 0

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
0 条
当前快照
1 份
快照标识符
@miqder21
此快照首次捕获于
2025/12/04 02:58
3 个月前
此快照最后确认于
2025/12/04 02:58
3 个月前
查看原文

前言

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

思路

先考虑每一个数。
数与数之间互不干扰,数位与数位之间也互不影响。只有数与数位会互相影响。二分图?
建一张二分图,左侧为 nn 个数,右侧为 6060 个二进制位。考虑连边。如果一个数 aia_i 二进制下的第 jj 位数为 11,会产生负贡献,那就连边。
显然,这是一个最大独立集问题,跑一遍匹配即可。因为每一个点仅会与另外一个点匹配。根据按位或的性质,如果两个数相同二进制位上的数都是 11,它还是 11,和二分图匹配的特点正好相同。因此没有问题。

代码

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

评论

0 条评论,欢迎与作者交流。

正在加载评论...