CodeForces

来源:互联网 发布:扫描答题软件 编辑:程序博客网 时间:2024/06/04 18:44

Qualification Rounds

题目链接:Qualification Rounds
Snark and Philip are preparing the problemset for the upcoming pre-qualification round for semi-quarter-finals. They have a bank of n problems, and they want to select any non-empty subset of it as a problemset.

k experienced teams are participating in the contest. Some of these teams already know some of the problems. To make the contest interesting for them, each of the teams should know at most half of the selected problems.

Determine if Snark and Philip can make an interesting problemset!

Input
The first line contains two integers n, k (1 ≤ n ≤ 105, 1 ≤ k ≤ 4) — the number of problems and the number of experienced teams.

Each of the next n lines contains k integers, each equal to 0 or 1. The j-th number in the i-th line is 1 if j-th team knows i-th problem and 0 otherwise.

Output
Print “YES” (quotes for clarity), if it is possible to make an interesting problemset, and “NO” otherwise.

You can print each character either upper- or lowercase (“YeS” and “yes” are valid when the answer is “YES”).

Examples
input
5 3
1 0 1
1 1 0
1 0 0
1 0 0
1 0 0
output
NO
input
3 2
1 0
1 1
0 1
output
YES
Note
In the first example you can’t make any interesting problemset, because the first team knows all problems.

In the second example you can choose the first and the third problems.

题意:给定n个问题和K个人,给定每个人知道的问题列表,求能否找到一个非空问题集合,满足每个人知道的集合中问题数量都不超过集合总题数的一半。

思路:觉得是DP,无奈DP菜得很,所以GG了,下面是大佬的方法

如果有一个问题所有人都不知道,那么选这个问题肯定符合题意

接着有:当k<=4时,若存在合法方案,则一定存在选择2个问题的合法方案。

证明:对于选择偶数个问题的合法方案(奇数不优),假设方案中每个人都知道一半问题(最坏),试图从中得到选择2个问题的合法方案。

先得到三条易证的结论:

Ⅰ两个人知道区间互补,则找不到问题满足这两个人都不知道。

Ⅱ否则,至少存在一个问题满足这两个人都不知道。

Ⅲ多个人知道区间一致,则至少存在一个问题满足这多个人都不知道。

①若不存在Ⅰ,则把4个人分成2组,每组内由Ⅱ可得1个问题。如果2个问题一致说明这两人对应那两人区间分别一致,由Ⅲ可知交换搭档即可。

②若存在Ⅰ,则把互补分到不同组。若一个人和另外三个人都互补,另外三个人由Ⅲ得到1个问题,一个人再得到1个问题。

得证。

代码:

#include<stdio.h>int a[17];int main(){    int n,k;    scanf("%d%d",&n,&k);    while(n--)    {        int tot=0,x;        for(int i=0; i<k; ++i)            scanf("%d",&x),tot|=(x<<i);        ++a[tot];    }    for(int i=0; i<16; ++i)        for(int j=i; j<16; ++j)            if((i&j)==0&&a[i]&&a[j])                return 0*printf("YES\n");    printf("NO\n");    return 0;}