1. 程式人生 > >【Codeforces】868C. Qualification Rounds

【Codeforces】868C. Qualification Rounds

pen codeforce etc 說明 strong char ret span color

【題目】C. Qualification Rounds

【題意】給定n個問題和K個人,給定每個人知道的問題列表,求能否找到一個非空問題集合,滿足每個人知道的集合中問題數量都不超過集合總題數的一半。n<=10^5,k<=4。

【算法】數學結論

【題解】當k<=4時,結論:若存在合法方案,則一定存在選擇2個問題的合法方案

證明:對於選擇偶數個問題的合法方案(奇數不優),假設方案中每個人都知道一半問題(最壞),試圖從中得到選擇2個問題的合法方案。

先得到三條易證的結論:

Ⅰ兩個人知道區間互補,則找不到問題滿足這兩個人都不知道。

Ⅱ否則,至少存在一個問題滿足這兩個人都不知道。

Ⅲ多個人知道區間一致,則至少存在一個問題滿足這多個人都不知道。

①若不存在Ⅰ,則把4個人分成2組,每組內由Ⅱ可得1個問題。如果2個問題一致說明這兩人對應那兩人區間分別一致,由Ⅲ可知交換搭檔即可。

②若存在Ⅰ,則把互補分到不同組。若一個人和另外三個人都互補,另外三個人由Ⅲ得到1個問題,一個人再得到1個問題。

得證。

技術分享
#include<cstdio>
#include<cstring>
#include<cctype>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int read(){
    
char c;int s=0,t=1; while(!isdigit(c=getchar()))if(c==-)t=-1; do{s=s*10+c-0;}while(isdigit(c=getchar())); return s*t; } /*------------------------------------------------------------*/ const int inf=0x3f3f3f3f; int n,kind,a[100010]; bool c[10000]; int main(){ n=read();kind=read(); for(int
i=1;i<=n;i++){ for(int j=1;j<=kind;j++)a[i]=(a[i]<<1)+read(); c[a[i]]=1; } if(c[0]){printf("YES");return 0;} for(int i=1;i<(1<<kind);i++)if(c[i]){ int x=i^((1<<kind)-1); for(int j=1;j<(1<<kind);j++)if(c[j]&&(x&j)==j){printf("YES");return 0;} } printf("NO"); return 0; }
View Code

【Codeforces】868C. Qualification Rounds