思维
题目大意
n n n 个人,给出 m m m 天每天可以选的人。现在每天要选一个人,问能否构造一组答案,使得没有人被选的次数大于 ⌈ m 2 ⌉ \lceil \frac m 2 \rceil ⌈2m⌉。
解题思路
竟然是很简单的思维题,分类一下就行了
我们只需要考虑只能选他一人的天数大于 ⌈ m 2 ⌉ \lceil \frac m 2 \rceil ⌈2m⌉ 的人的情况。
即:设有一人编号是 i i i,他可以被选的次数为 c n t i cnt_i cnti,如果找不到一个 c n t i cnt_i cnti 满足 c n t i > ⌈ m 2 ⌉ cnt_i \gt \lceil \frac m 2 \rceil cnti>⌈2m⌉,说明我们不管怎么选,最后都不会超,都满足要求。
如果存在 c n t i > ⌈ m 2 ⌉ cnt_i \gt \lceil \frac m 2 \rceil cnti>⌈2m⌉,按照如下步骤考虑:
设 i i i 必须被选的天数为 c n t x cnt_x cntx。
1.判断 c n t x cnt_x cntx 是否大于 ⌈ m 2 ⌉ \lceil \frac m 2 \rceil ⌈2m⌉。如果大于,说明肯定不符合要求。
2.反之,若 c n t x ≤ ⌈ m 2 ⌉ cnt_x \le \lceil \frac m 2 \rceil cntx≤⌈2m⌉,则把 ⌈ m 2 ⌉ − c n t x \lceil \frac m 2 \rceil - cnt_x ⌈2m⌉−cntx 的都分给 i i i。这样就满足了不会有别的人,被选的次数超过 ⌈ m 2 ⌉ \lceil \frac m 2 \rceil ⌈2m⌉ 。由 c n t x ≤ ⌈ m 2 ⌉ cnt_x \le \lceil \frac m 2 \rceil cntx≤⌈2m⌉ 可知 ⌈ m 2 ⌉ − c n t x ≥ 0 \lceil \frac m 2 \rceil - cnt_x \ge 0 ⌈2m⌉−cntx≥0,所以这个操作是可以实现的~
参考代码
#include<stdio.h>
#include<iostream>
#include<vector>
#include<cstring>
#include<cstdio>
#include<climits>
#include<cmath>
#include<algorithm>
#include<queue>
#include<deque>
#include<map>
#include<unordered_map>
#include<set>
#include<unordered_set>
#include<stack>
//#define LOCAL //提交时一定注释
#define VI vector<int>
#define eps 1e-6
#define io ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
typedef long long LL;
typedef double db;
const int inf = 0x3f3f3f3f;
const LL INF = 1e18;
const int N = 1e5 + 10;
#define ls rt << 1
#define rs rt << 1 | 1
#define lson l, mid, rt << 1
#define rson mid + 1, r, rt << 1 | 1
inline int readint() {int x; scanf("%d", &x); return x;}
int cnt[N], res[N];
set<int> day[N];
int n, m;
void init() {
for(int i = 1; i <= m; ++i) {
day[i].clear();
}
memset(cnt, 0, sizeof(cnt));
memset(res, 0, sizeof(res));
}
int main() {
#ifdef LOCAL
freopen("input.txt", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
int t = readint();
while (t--) {
init();
n = readint(), m = readint();
for(int i = 1; i <= m; ++i) {
int k = readint();
while (k--) {
int p = readint();
day[i].insert(p);
cnt[p]++;
}
}
int ma = 0, lim = (m + 1) / 2;
for(int i = 1; i <= n; ++i) {
if (cnt[i] > lim) {
ma = i; break;
}
}
if (ma == 0) {
printf("YES\n");
for(int i = 1; i <= m; ++i) {
auto it = day[i].begin();
printf("%d%s", *it, i == m ? "\n" : " ");
}
continue;
}
int num = 0;
for(int i = 1; i <= m; ++i) {
if (res[i]) continue;
if (day[i].size() == 1 && day[i].find(ma) != day[i].end()) {
res[i] = ma;
num++;
}
}
if (num > lim) {
printf("NO\n"); continue;
}
for(int i = 1; i <= m; ++i) {
if (res[i]) continue;
if (day[i].find(ma) != day[i].end() && num < lim) {
res[i] = ma;
num++;
continue;
}
for(auto it = day[i].begin(); it != day[i].end(); ++it) {
int now = *it;
if (now != ma) {
res[i] = now;
break;
}
}
}
printf("YES\n");
for(int i = 1; i <= m; ++i) {
printf("%d%s", res[i], i == m ? "\n" : " ");
}
}
return 0;
}