题解 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;
}