题解 CF1598B Groups

\[\text{题目大意} \]

\(\quad\)\(n\) 个学生,每个学生在周一到周五有些天可以上课(用 \(1\) 表示),其余的时间则不能上课(用 \(0\) 表示),问是否有一种分法,将 \(n\) 名学生分成大小为 \(\frac{n}{2}\) 的两组( \(n\) 为偶数),满足组内所有学生都可以选择共同的一天上课,且两组学生选择的时间不一样。

\[\text{思路} \]

\(\quad\)考虑容斥原理,先用 \(cnt_i\) 表示第 \(i\) 天(星期 \(i\) )可以上课的学生数量,用 \(num_{i,j}\) 表示第 \(i\) 天和第 \(j\)可以上课的学生数量。

\(\quad\)先选择两个不同的时间 \(i,j\),满足以下条件即可完成分组:

\[ \left\{ \begin{aligned} & cnt_i\times 2\geq n\\ & cnt_j\times 2\geq n\\ & cnt_i+cnt_j-num_{i,j}= n \end{aligned} \right. \]

\(\quad\)前两个条件很好理解,关键就是第三个条件怎么推的。

\(\quad\)\(x=cnt_i-num_{i,j},y=cnt_j-num_{i,j}\)\(x\) 的意义是只可以上第 \(i\) 天课的人(这里只考虑 \(i,j\) 两天),\(y\) 的意义是只可以上第 \(j\) 天课的人。

\(\quad\)又因为 \(num_{i,j}\) 表示 \(i,j\) 两天都可以上的人,可以发现 \(x,y,num_{i,j}\) 没有并集(没有人同时在两个集合),\(num_{i,j}\) 可以选择第 \(i\) 天上课(加入\(x\)),也可以选择第 \(j\) 天上课(加入 \(y\)),只要满足 \(x+y+num_{i,j}= n\) 即可,经过化简就是:

\[cnt_i+cnt_j-num_{i,j}= n \]

\(\quad\)这里我用数位的方法保存 \(num\) 数组,其实直接用二维数组就可以了。

\(\quad\)注意:多组数据,记得清空数组。

const int N=1e3+5;
int T,n,ans,mid,cnt[6],num[70];
vector<int>t[N];
signed main()
{
	T=read();
	while(T--){
		n=read();ans=0;mid=n/2;
		memset(cnt,0,sizeof(cnt));
		memset(num,0,sizeof(num));
		for(re i=1;i<=n;i++)
		{
			t[i].clear();
			for(re j=1;j<=5;j++)
			{
				bool b=read();
				if(b)cnt[j]++,t[i].push_back(j);
			}
			if(t[i].size()==1)continue;
			for(re j=0;j<t[i].size();j++)
			{
				int x=1<<t[i][j];
				for(re k=j+1;k<t[i].size();k++)
				{
					int y=x|(1<<t[i][k]);
					num[y]++;
				}
			}
		}
		for(re i=1;i<5;i++)
		{
			if(cnt[i]*2<n)continue;
			for(re j=i+1;j<=5;j++)
			{
				if(cnt[j]*2<n)continue;
				int x=cnt[i],y=cnt[j],z=num[(1<<i)|(1<<j)],p;
				if(x+y-z==n){ans=1;break;}
			}
			if(ans)break;
		}
		puts(ans?"YES":"NO");
	}
	return 0;
}
posted @ 2021-10-25 21:18  Farkas_W  阅读(59)  评论(0编辑  收藏  举报