zoukankan      html  css  js  c++  java
  • [CF538H]Summer Dichotomy

    [CF538H]Summer Dichotomy

    题目大意:

    ​ 将若干个学生分为两个班级(S_1,S_2),每个班的学生数分别为(n_1,n_2)(甚至可以没有学生,也可以没有老师)。给出限制(t_{min},t_{max}),要求(t_{min}le n_1+n_2le t_{max})。有(n(nle10^5))个老师,每个老师希望他所任教的班级人数在([l_i,r_i])范围内。有(m(mle10^5))对老师之间有一些私人恩怨,不能分在一个班级。问是否存在合法的分班方案。如果有,求出其中的任意一种,输出每个班的总人数以及各个老师所任教的班级。

    思路:

    ​ 对于所有([l_i,r_i])的限制,我们不妨假设(n_1=min{r_i},n_2=max{l_i}),显然这是比较松的约束。再考虑(t_{min},t_{max})的限制,确定可行的一组(n_1,n_2)。考虑二分图染色构造老师分配的方案。对于只能分到(S_1)或只能分到(S_2)的老师DFS遍历染色,若更新到的结点与已染色结点矛盾,说明根本不是二分图,不存在合法的方案。对于两个都不可以分进去的,说明也不存在合法方案。最后再对于(S_1)(S_2)都可以的进行染色。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    #include<climits>
    inline int getint() {
    	register char ch;
    	while(!isdigit(ch=getchar()));
    	register int x=ch^'0';
    	while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    	return x;
    }
    constexpr int N=1e5;
    int l[N],r[N],ans[N];
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
    	e[u].push_back(v);
    	e[v].push_back(u);
    }
    void dfs(const int &x,const int &c) {
    	if(ans[x]) {
    		if(ans[x]!=c) throw(0);
    		return;
    	}
    	ans[x]=c;
    	for(auto &y:e[x]) {
    		dfs(y,3-c);
    	}
    }
    int main() {
    	const int t_min=getint(),t_max=getint();
    	const int n=getint(),m=getint();
    	int n1=INT_MAX,n2=INT_MIN;
    	for(register int i=0;i<n;i++) {
    		n2=std::max(n2,l[i]=getint());
    		n1=std::min(n1,r[i]=getint());
    	}
    	if(n1+n2<t_min) n2=t_min-n1;
    	else if(n1+n2>t_max) n1=t_max-n2;
    	if(n1<0||n2<0) {
    		puts("IMPOSSIBLE");
    		return 0;
    	}
    	for(register int i=0;i<m;i++) {
    		add_edge(getint()-1,getint()-1);
    	}
    	for(register int i=0;i<n;i++) {
    		try {
    			if(!(l[i]<=n1&&n1<=r[i])&&!(l[i]<=n2&&n2<=r[i])) throw(0);
    			if((l[i]<=n1&&n1<=r[i])&&!(l[i]<=n2&&n2<=r[i])) dfs(i,1);
    			if((l[i]<=n2&&n2<=r[i])&&!(l[i]<=n1&&n1<=r[i])) dfs(i,2);
    		} catch(...) {
    			puts("IMPOSSIBLE");
    			return 0;
    		}
    	}
    	for(register int i=0;i<n;i++) {
    		try {
    			if(!ans[i]) dfs(i,1);
    		} catch(...) {
    			puts("IMPOSSIBLE");
    			return 0;
    		}
    	}
    	puts("POSSIBLE");
    	printf("%d %d
    ",n1,n2);
    	for(register int i=0;i<n;i++) {
    		printf("%d",ans[i]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    c# 扩展方法奇思妙用
    AnkhSVN的自动加锁
    C#数组学习
    同一IP下多端口网站共享cookie的问题
    瞎子摸象销售开票(一)
    瞎子摸象年结
    配置WSS3.0搜索功能的步骤
    瞎子摸象销售开票(二)
    瞎子摸象汇兑损益
    ajax+php鼠标拖动层至任意位置并实时保存
  • 原文地址:https://www.cnblogs.com/skylee03/p/9084408.html
Copyright © 2011-2022 走看看