[CF538H] Summer Dichotomy 题解
Description
有 \(T\) 名学生,你要从中选出至少 \(t\) 人,并将选出的人分成两组,可以有某一组是空的。
有 \(n\) 名老师,每名老师要被分配到两个小组之一,对于第 \(i\) 名老师,要求所在的小组中的学生人数 \(\in [l_i, r_i]\)
此外,有 \(m\) 对老师不能在同一个小组中。
你需要判断能否满足所有要求,如果可以,请给出一种方案。
\(t \le T \le 10^9,n,m \le 10^5\)
Sol
首先给出一个结论:在不考虑 \(T,t\) 限制时,当两组人数为 \(\max_{i=1}^n l_i\) 与 \(\min_{i=1}^n r_i\) 时,区间最大。
证明如下:当存在三个老师的 \([l, r]\) 两两无交时,肯定是无解的。
剩下的情况假设二值为 \(n_1, n_2\),我们再分两种情况讨论:
-
\(n_1 \ge n_2\),容易发现所有老师都可以选任意一组加人。
-
\(n_1 < n_2\),容易发现当 \(n_1\) 减小或 \(n_2\) 增大时,都有老师的选择范围受到限制,所以当前区间最优。
考虑加人 \(T,t\) 的限制,因为 \(n_1\) 只能增大,\(n_2\) 只能减小,那么我们只需从 \(n_1\) 和 \(n_2\) 上面增减即可。
判断方案用二分图染色即可。
时间复杂度 \(\mathcal{O}(n+m)\)
Code
#include<bits/stdc++.h>
using namespace std;
inline int Read() {
int x = 0, f = 1; char ch = getchar();
while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar();}
while(isdigit(ch)) {x = (x << 3) + (x << 1) + ch - '0'; ch = getchar();}
return x * f;
}
int first[500005], nxt[500005], to[500005], tot;
void Add(int x, int y) {nxt[++tot] = first[x]; first[x] = tot; to[tot] = y;}
int T, t, n, m, l[100005], r[100005], col[100005], mxl, mnr = 1E9;
void dfs(int u, int Col) {
if(col[u]) {
if(col[u] != Col) {
puts("IMPOSSIBLE");
exit(0);
}
return ;
}
col[u] = Col;
for(int e = first[u]; e; e = nxt[e]) {
int v = to[e];
dfs(v, 3 - Col);
}
}
signed main() {
t = Read(), T = Read();
n = Read(); m = Read();
for(int i = 1; i <= n; i++)
l[i] = Read(), r[i] = Read(), mxl = max(mxl, l[i]), mnr = min(mnr, r[i]);
if(mxl + mnr > T) mnr -= (mxl + mnr - T);
if(mxl + mnr < t) mxl += (t - mxl - mnr);
if(mxl < 0 || mnr < 0) return puts("IMPOSSIBLE"), 0;
for(int i = 1; i <= m; i++) {
int x = Read(), y = Read();
Add(x, y); Add(y, x);
}
for(int i = 1; i <= n; i++) {
int flag1 = (l[i] <= mxl && mxl <= r[i]), flag2 = (l[i] <= mnr && mnr <= r[i]);
if(!flag1 && !flag2) return puts("IMPOSSIBLE"), 0;
if(flag1 && !flag2) dfs(i, 1);
if(flag2 && !flag1) dfs(i, 2);
}
for(int i = 1; i <= n; i++)
if(!col[i]) dfs(i, 1);
puts("POSSIBLE");
cout << mxl << " " << mnr << endl;
for(int i = 1; i <= n; i++)
printf("%d", col[i]);
return 0;
}