题解 CF538H 【Summer Dichotomy】

xht

2020-01-13 02:37:15

Solution

> [CF538H Summer Dichotomy](https://codeforces.com/contest/538/problem/H) ## 题意 - 有 $T$ 名学生,你要从中选出至少 $t$ 人,并将选出的人分成两组,可以有某一组是空的。 - 有 $n$ 名老师,每名老师要被分配到两个小组之一,对于第 $i$ 名老师,要求所在的小组中的学生人数 $\in [l_i, r_i]$。 - 此外,有 $m$ 对老师不能在同一个小组中。 - 你需要判断能否满足所有要求,如果可以,请给出一种方案。 - $t \le T \le 10^9$,$n,m \le 10^5$。 ## 题解 先不考虑 $t,T$ 的限制,可以证明 $n_1 = \min_{i=1}^n r_i$,$n_2 = \max_{i=1}^n l_i$ 是最优的。 证明如下: 将所有 $[l_i, r_i]$ 当作一条数轴上的线段,那么有三种情况: 1. 有三条线段两两不交,则无解。 2. 所有线段两两有交,即有 $n_1 \ge n_2$,则在这种情况下,每个老师都可以随意的选择小组。 3. $n_1 < n_2$,在这种情况下,显然 $n_1$ 不能更大,而更小则不优,$n_2$ 同理。 因此 $n_1 = \min_{i=1}^n r_i$,$n_2 = \max_{i=1}^n l_i$ 一定是最优的。 如果考虑 $t,T$ 的限制呢?可以发现,若 $n_1 + n_2 < t$,则无论哪种情况下,只增大 $n_2$ 是最优的;若 $n_1 + n_2 > T$,则无论哪种情况下,只减小 $n_1$ 的最优的。 因此我们可以直接求出最优的 $n_1,n_2$,最后做一次二分图染色即可。 时间复杂度 $\mathcal O(n+m)$。 ## 代码 ```cpp #define Fail return prints("IMPOSSIBLE"), 0 const int N = 1e5 + 7; int t, T, n, m, l[N], r[N], n1 = 1e9 + 1, n2 = -1, c[N]; vi e[N]; inline bool pd(int x, int i) { return l[i] <= x && x <= r[i]; } bool dfs(int x) { for (auto y : e[x]) if (!c[y]) { c[y] = 3 - c[x]; if (!dfs(y)) return 0; } else if (c[x] == c[y]) return 0; return 1; } int main() { rd(t), rd(T), rd(n), rd(m); for (int i = 1; i <= n; i++) rd(l[i]), rd(r[i]), n1 = min(n1, r[i]), n2 = max(n2, l[i]); if (n1 + n2 < t) n2 = t - n1; if (n1 + n2 > T) n1 = T - n2; if (n1 < 0 || n2 < 0) Fail; for (int i = 1; i <= n; i++) { bool o1 = pd(n1, i), o2 = pd(n2, i); if (!o1 && !o2) Fail; if (o1 && !o2) c[i] = 1; if (!o1 && o2) c[i] = 2; } for (int i = 1, x, y; i <= m; i++) rd(x), rd(y), e[x].pb(y), e[y].pb(x); for (int i = 1; i <= n; i++) if (c[i] && !dfs(i)) Fail; for (int i = 1; i <= n; i++) if (!c[i]) { c[i] = 1; if (!dfs(i)) Fail; } string ans = ""; for (int i = 1; i <= n; i++) ans += c[i] + '0'; prints("POSSIBLE"), print(n1, ' '), print(n2), prints(ans); return 0; } ```