Z与黄焖鸡 增强 二分

看到最小值最大一般会想到二分。

二分mid,把a中大于等于mid的看成1,小于mid的看成0。

对于每一行的0和1,我们能把这一行看成二进制中的一个数,设这个二进制数是c[i]。

如果能找到两行,这两行的c或运算起来全是1,那mid就是合法的。

也就是说,对于c[i],如果存在c[j],满足c[j]|(((1<<m)-1)^c[i])=c[j],那就说明mid是合法的。

处理一个vis数组,vis[i]表示是否存在某一个c[k]满足c[k]|vis[i]=c[k]即可。

vis的处理可以补位处理

#include<iostream>
#include<cstdio>
using namespace std;
int n,m,l,r,ans;
const int N=100010,M=16;
int a[N][M],vis[(1<<15)+10];
int check(int mid)
{
	for(int i=0,maxx=(1<<m)-1;i<=maxx;++i)vis[i]=0;
	for(int i=1,now;i<=n;++i)
	{
		now=0;
		for(int j=1;j<=m;++j)
			if(a[i][j]>=mid)now|=1<<(j-1);
		vis[now]=1;
	}
	for(int i=(1<<(m-1))-1;i>=0;--i)
		for(int j=1;j<=m;++j)
			if(!(i&(1<<(j-1))))vis[i]|=vis[i|(1<<(j-1))];
	for(int i=1,now;i<=n;++i)
	{
		now=0;
		for(int j=1;j<=m;++j)
			if(a[i][j]>=mid)now|=1<<(j-1);
		if(vis[((1<<m)-1)^now])return 1;
	}
	return 0;
}
int main()
{
	cin>>n>>m;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=m;++j)scanf("%d",&a[i][j]);
	l=-1;r=1e9+1;
	while(l<=r)
	{
		int mid=(l+r)>>1;
		if(check(mid))
		{
			ans=mid;
			l=mid+1;
		}
		else r=mid-1;
	}
	cout<<ans;
	return 0;
}
posted @ 2021-12-22 18:54  wljss  阅读(62)  评论(0编辑  收藏  举报