题目链接:Qualification Rounds
题意:给出n,k。n个题目,k个人,k个人中每个人做过那个题目的关系也给出来。现在问能不能在这n个题目中选出一定数量的题组成一个题集,使得k个人中的任何一个人在这个题集中做过的题不超过题数的一半。
思路:刚开始想到,如果有一题k个人都做过,那么这一题绝对不选,如果有一题k个人都没做过,直接可以输出“YES”,问题在于那些完成的人数>0且< k的题里面,接着就想到了如果选两题就能输出“YES”的话,那么这两题一定没有交集;选3题输出“YES”的话,那么3题中的两题必须没有交集,否则意味着有一个人做过3题中的两题,大于1/2了。选四题,选五题…要输出“YES”,至少都要求存在两个题做过的人没有交集。
所以,只需要判断存不存在两个题,使得两个题做过的人没有交集。由于题目数n高达1e5,n^2遍历铁定超时,而k最大只有4,所以这题关键在于状态压缩再枚举状态。存状态,状态最多只有16种,0000~1111,枚举状态,如果状态存在且作与运算结果为0,证明两个状态没有交集,输出“YES”。
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
#define Max(a,b) a>b?a:b
#define Min(a,b) a>b?b:a
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;
typedef long long ll;
int dir[4][2]= {{1,0},{-1,0},{0,1},{0,-1}};
const double eps = 1e-6;
const double Pi = acos(-1.0);
const int INF=0x3f3f3f3f;
const int MOD = 1e9+7;
const int maxn = 1e5+10;
int mat[maxn][4],num[4];
int main(){
int n,k;
int state,x;
int vis[20];
while(~scanf("%d%d",&n,&k)){
mem(vis,0);
for(int i = 0; i < n; i++){
state = 0;
for(int j = 0; j < k; j++){
scanf("%d",&x);
state += (1 << j) * x;
}
vis[state] = 1;
}
bool flag = false;
for(int i = 0; i < 16; i++){
for(int j = 0; j < 16; j++){
if(vis[i] && vis[j] && (i & j) == 0){
flag = true;
}
}
}
if(flag) puts("YES");
else puts("NO");
}
return 0;
}