Codeforces 468B Two Sets(超直白解释)

来源:互联网 发布:ubuntu创建用户和目录 编辑:程序博客网 时间:2024/04/28 03:07

题意:

给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:

若x在集合A中,则a-x必须也在集合A中。

若x在集合B中,则b-x必须也在集合B中。

思路:

对于一个x来说,能分成以下4种情况(这里a!=b):

1.a-x不存在,b-x不存在。这种情况直接输出NO。

2.a-x存在,b-x不存在。这种情况把x和a-x放在集合A中。

3.a-x不存在,b-x存在。这种情况把x和b-x放在集合B中。

4.a-x存在,b-x存在。这种情况比较我们就不能直接确定要放A还是要放B了。

那么我们接下还需要判断是否存在y有a-y=b-x或者b-y=a-x其中之一存在。为什么是其中之一呢?假设有a-y=b-x和b-y=a-x同时存在,那么将两式子相减有x-y=y-x -> x*2=y*2 -> x=y成立,则有a-y=a-x=b-x -> a=b矛盾。所以上面两种情况只可能存在一种或都不存在。如果存在a-y=b-x,那么就把x和a-x和y和a-y(b-x)都放到集合A中。同理b-y=a-x存在的情况。如果都不存在,那么我们就无法决则把x和a-x和b-x放到集合A中还是集合B中,因为放到那一边都会剩下另一个无法去放,所以就输出NO。这里用并查集来维护即可。

#include<cstdio>#include<map>#include<algorithm>using namespace std;const int MAX=1e5+5;int n,a,b,p[MAX],fa[MAX];map<int,int> mp;int Find(int x){int r=x,t;while(r!=fa[r]){r=fa[r];}while(x!=r){t=fa[x];fa[x]=r;x=t;}return r;}void Union(int u,int v){int uu=Find(u);int vv=Find(v);if(uu!=vv){fa[uu]=v;;}}int main(){scanf("%d%d%d",&n,&a,&b);int Max=0;for(int i=1;i<=n;i++){scanf("%d",&p[i]);mp[p[i]]=i;Max=max(Max,p[i]);}if(Max>=max(a,b)) printf("NO\n");else{for(int i=0;i<=n+1;i++){fa[i]=i;}for(int i=1;i<=n;i++){if(mp[a-p[i]]) Union(i,mp[a-p[i]]);else Union(i,n+1);if(mp[b-p[i]]) Union(i,mp[b-p[i]]);else Union(i,0);}int A=Find(0);int B=Find(n+1);if(A!=B){printf("YES\n");for(int i=1;i<=n;i++){if(i!=1) printf(" ");if(Find(i)==A) printf("0");else printf("1");}printf("\n");}else printf("NO\n");}return 0;}


0 0
原创粉丝点击