CF538H Summer Dichotomy题解

题目链接:CF538H

反思

刚开始执意想先跑二分图,然后计算n1,n2合法的区间,结果反而非常难以计算,其实稍一转弯,先计算n1,n2,再跑二分图,一切就明朗了许多

有些时候,如果有两种思考方法,不要死磕一种,两种都尝试一下

solution

  • 设第一组人数为n1,第二组为n2

  • 我们不妨先不考虑t,T的限制

  • 考虑直接构造出n1,n2,我们不妨思考,如果所有区间都有交,那么所有老师都可以任意选择区间

  • 否则必然是有两个区间无交(3个及以上直接无解),然后剩下所有区间都靠到两个区间上

  • 我们不妨令\(n2 = \max\{l_i\},n1 = \min\{r_i\}\),注意这样能最大可能的包含所有合法情况

  • 稍一画图便可知道,假设我们一直维护两个区间[l1,r1],[l2,r2]分别表示最终状态中,n1,n2可行的区间,则r1,l2始终不会改变,即为我们构造的n1,n2,会减小|增大的,只有l1,r2

  • 那么接着考虑若\(n1 + n2 < T\)怎么办,注意到n1已经是区间右端点了,我们只可能增大n2,令\(n2 = T - n1\)

  • 同理,若\(n1 + n2 > t\),令\(n1 = t - n2\)

  • 得到n1,n2后,若有某个老师两个组都分不进去,无解,若某个老师只能分进某个组,提前确定,剩下的,待定,连边二分图染色即可

代码如下(n1,n2和题解描述的反过来了)

/*CF538H Summer Dichotomy*/
#include<bits/stdc++.h>
using namespace std;
int read(){
	char c = getchar();
	int x = 0;
	while(c < '0' || c > '9')	c = getchar();
	while(c >= '0' && c <= '9')	x = x * 10 + c - 48,c = getchar();
	return x;
} 
int T,t,n;
const int _ = 1e6 + 7;
vector<int>E[_];
int lx,rx,ly,ry;
typedef pair<int,int> pii;
typedef pair<pii,pii> PII;
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define fail return puts("IMPOSSIBLE"),0
pii p[_];
PII P[_];int cnt = 0;
int c[_];
bool in(pii A,int x){
	int l = A.fi,r = A.se;
	return x <= r && x >= l;
}
bool dfs(int u){
	for(auto v:E[u]){
		if(!c[v]){
			c[v] = 3 - c[u];
			if(!dfs(v))	return 0;
		}
		else if(c[v] == c[u])	return 0;
	}
	return 1;
}
int main(){
	t = read(),T = read();
	n = read();int m = read();
	int n1 = 0,n2 = 1e9;
	for(int i = 1; i <= n; ++i){
		int l = read(),r = read();
		p[i] = mp(l,r); 
		n1 = max(n1,l),n2 = min(n2,r);
	}
	if(n1 + n2 < t)		n1 = t - n2;
	if(n1 + n2 > T)		n2 = T - n1;
//	cout<<n1<<' '<<n2<<'\n';
	if(n1 < 0 || n2 < 0)	fail;
	for(int i = 1; i <= m; ++i){
		int u = read(),v = read();
		E[u].pb(v);E[v].pb(u);
	}
	for(int i = 1; i <= n; ++i){
		bool o1 = in(p[i],n1);
		bool o2 = in(p[i],n2);
		if(!o1 && !o2)	fail;
		if(o1 && o2)	continue;
		if(o1)	c[i] = 1;
		else	c[i] = 2;
	}
	for(int i = 1; i <= n; ++i){
		if(c[i]){
			if(!dfs(i))	fail;
		}
	}
	for(int i = 1; i <= n; ++i){
		if(!c[i]){
			c[i] = 1;
			if(!dfs(i))	fail;
		}
	}
	puts("POSSIBLE");
	cout<<n1<<' '<<n2<<'\n';
	for(int i = 1; i <= n; ++i)	if(c[i] == 1)	putchar('1');else	putchar('2');
	return 0;
}
posted @ 2021-05-31 20:42  y_dove  阅读(113)  评论(0编辑  收藏  举报