(并查集\状态压缩)CodeForces - 469D Two Sets

Little X has n distinct integers: p1, p2, ..., pn. He wants to divide all of them into two sets A and B. The following two conditions must be satisfied:

  • If number x belongs to set A, then number a - x must also belong to set A.
  • If number x belongs to set B, then number b - x must also belong to set B.

Help Little X divide the numbers into two sets or determine that it's impossible.

Input

The first line contains three space-separated integers n, a, b (1 ≤ n ≤ 105; 1 ≤ a, b ≤ 109). The next line contains n space-separated distinct integers p1, p2, ..., pn (1 ≤ pi ≤ 109).

Output

If there is a way to divide the numbers into two sets, then print "YES" in the first line. Then print n integers: b1, b2, ..., bn (bi equals either 0, or 1), describing the division. If bi equals to 0, then pi belongs to set A, otherwise it belongs to set B.

If it's impossible, print "NO" (without the quotes).

Example

Input
4 5 9
2 3 4 5
Output
YES
0 0 1 1
Input
3 3 4
1 2 4
Output
NO

Note

It's OK if all the numbers are in the same set, and the other one is empty.

 

注意到如果x存在于A果a-x、b-x(如果存在)也必须存在在A,如果a-(b-x) 、b-(a-x)存在也必须在A……即所有数可以划分为若干个集合,每个集合中的元素必须同时属于A或B。这可以通过并查集维护。如果某数x,a-x,b-x都不存在那么这个数无法放到A、B任何一个,直接输出NO即可。

接下来维护并查集的状态,采用状态压缩,用两位2进制数表示可否放到A、B集合中。对于每个数x,如果a-x存在则其可以放在集合A,如果b-x存在则其可以放在集合B。对每个并查集取其集合内所有可行状态的交集。显然并查集之间是不再存在互相影响的。如果每个并查集可行状态非0就表明一定存在符合题意的分配方式,任取每个集合的任意可行分配即可。

  1 #include <iostream>
  2 #include <string>
  3 #include <algorithm>
  4 #include <cstring>
  5 #include <cstdio>
  6 #include <cmath>
  7 #include <queue>
  8 #include <set>
  9 #include <map>
 10 #include <list>
 11 #include <vector>
 12 #include <stack>
 13 #define mp make_pair
 14 //#define P make_pair
 15 #define MIN(a,b) (a>b?b:a)
 16 //#define MAX(a,b) (a>b?a:b)
 17 typedef long long ll;
 18 typedef unsigned long long ull;
 19 const int MAX=1e5+5;
 20 const int MAX_V=25;
 21 const int INF=2e9+5;
 22 const double M=4e18;
 23 using namespace std;
 24 const int MOD=1e9+7;
 25 typedef pair<ll,int> pii;
 26 const double eps=0.000000001;
 27 #define rank rankk
 28 map<int,int> par;//父亲
 29 map<int,int> rank;//树的高度
 30 //初始化n个元素
 31 map<int,bool> chu;
 32 map<int,int> st;
 33 int an[MAX];
 34 void init(int n)
 35 {
 36     for(int i=1;i<n;i++)
 37     {
 38         par[i]=i;
 39         rank[i]=0;
 40     }
 41 }
 42 //查询树的根,期间加入了路径压缩
 43 int find(int x)
 44 {
 45     if(!par[x])
 46     {
 47         rank[x]=0;
 48         return par[x]=x;
 49     }
 50     if(par[x]==x)
 51         return x;
 52     else
 53         return par[x]=find(par[x]);
 54 }
 55 //合并x和y所属的集合
 56 void unite(int x,int y)
 57 {
 58     x=find(x);
 59     y=find(y);
 60     if(x==y)
 61         return ;
 62     if(rank[x]<rank[y])
 63         par[x]=y;
 64     else
 65     {
 66         par[y]=x;
 67         if(rank[x]==rank[y])
 68             rank[x]++;
 69     }
 70 }
 71 //判断x和y是否属于同一个集合
 72 bool same(int x,int y)
 73 {
 74     return find(x)==find(y);
 75 }
 76 int n,a,b;
 77 int x[MAX];
 78 int main()
 79 {
 80     scanf("%d%d%d",&n,&a,&b);
 81     for(int i=1;i<=n;i++)
 82     {
 83         scanf("%d",&x[i]);
 84         chu[x[i]]=true;
 85     }
 86     for(int i=1;i<=n;i++)
 87         st[x[i]]=0;
 88     for(int i=1;i<=n;i++)
 89     {
 90         bool sta=false;
 91         if(chu[a-x[i]])
 92         {
 93             sta=true;
 94             unite(x[i],a-x[i]);
 95             st[x[i]]|=1;
 96         }
 97         if(chu[b-x[i]])
 98         {
 99             sta=true;
100             unite(x[i],b-x[i]);
101             st[x[i]]|=2;
102         }
103         if(!sta)
104             return 0*printf("NO\n");
105     }
106     for(int i=1;i<=n;i++)
107     {
108         st[find(x[i])]&=st[x[i]];
109     }
110     for(int i=1;i<=n;i++)
111         if(!st[x[i]])
112             return 0*printf("NO\n");
113     printf("YES\n");
114     for(int i=1;i<=n;i++)
115     {
116         if(st[find(x[i])]&1)
117             printf("0 ");
118         else
119             printf("1 ");
120     }
121     printf("\n");
122     return 0;
123 }

 

转载于:https://www.cnblogs.com/quintessence/p/6993306.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值