CF1619D New Year's Problem

洛谷题面

题目大意

\(\rm Vlad\)\(n\) 个朋友,每个朋友需要且仅需要 \(1\) 个礼物。有 \(m\) 家礼物商店,如果在第 \(i\) 个商店中为朋友 \(j\) 买礼物,朋友 \(j\) 将获得 \(p_{i,j}\) 的快乐值。

由于时间紧迫,\(\rm Vlad\) 最多只会在 \(n-1\) 家不同的商店中买礼物。请你使每位朋友能获得的快乐值中的最小值最大。

题目分析

看到类似求“最大值最小”“最小值最大”的题马上想到二分答案。

所以我们二分快乐值。

对于每一个快乐值,我们怎么判断它不可行呢?

两种情况:有一个人没有礼物和所有店都只能满足一个人(因为是选择 \(n-1\) 家店,所以可行必定至少有一家店满足的人数大于等于 \(2\))。


一个小 \(\rm trick\):

遇到题目中这种 \(n\times m\) 的和不超过 \(10^5\) 的题目,开二维数组的话,\(n,m\) 的具体范围未知,可能会导致 \(\verb!MLE!\)

解决办法有两个:

  • \(\mathbf{vector}\)

  • 压缩成一维数组。

也就是:

a[(i-1)*m+j]=a[i][j]

可以有效减少内存。

代码

//2022/1/11

const int ma=1e5+5;

int a[ma];

int T,n,m;

inline bool check(int now)
{
	for(register int i=1;i<=m;i++)
	{
		bool mark=true;
		
		for(register int j=1;j<=n;j++)
		{
			if(a[(j-1)*m+i]>=now)
			{
				mark=false;
			}
		}
		
		if(mark==true)//一个人的礼物在哪家店都买不到 
		{
			return false;
		}
	}
	
	for(register int i=1;i<=n;i++)
	{
		int num(0);
		
		for(register int j=1;j<=m;j++)
		{
			if(a[(i-1)*m+j]>=now)
			{
				num++;
			}
		}
		
		if(num>=2)//有一家店至少能同时买到至少两个人的礼物
		{
			return true;
		}
	}
	
	return false;
}

inline int binary()
{
	int l=1,r=1e9;
	
	//枚举快乐值 
	while(l<r)
	{
		int mid=(l+r+1)>>1;
		
		if(check(mid)==true)
		{
			l=mid;
		}
		
		else
		{
			r=mid-1;
		}
	}
	
	return l;
}

inline void solve()
{
	mst(a,0);
	
	n=read(),m=read();
	
	for(register int i=1;i<=n;i++)
	{
		for(register int j=1;j<=m;j++)
		{
			a[(i-1)*m+j]=read();
		}
	}
	
	printf("%d\n",binary()); 
}

int main(void)
{
	T=read();
	
	while(T--)
	{
		solve();
	}
	
	return 0;
}
posted @ 2022-01-11 22:14  Coros_Trusds  阅读(129)  评论(0)    收藏  举报