链接:https://www.nowcoder.com/acm/contest/77/D
来源:牛客网
时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld
题目描述
给你a,b和n个数p[i],问你如何分配这n个数给A,B集合,并且满足:
若x在集合A中,则a-x必须也在集合A中。
若x在集合B中,则b-x必须也在集合B中。
输入描述:
第一行 三个数 n a b 1<=n<=1e5 1<=a,b<=1e9
第二行 n个数 p1 p2 p3...pn 1<=pi<=1e9
输出描述:
如果可以恰好分开就输出第一行 YES
然后第二行输出 n个数 分别代表pi 是哪个集合的 0 代表是A集合 1代表是B 集合
不行就输出NO
放在哪个集合都可以的时候优先放B
示例1
输入
4 5 9
2 3 4 5
输出
YES
0 0 1 1
示例2
输入
3 3 4
1 2 4
输出
NO
题意:
给你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 <bits/stdc++.h> using namespace std; const int Max = 1e5 + 5; map <int, int> mp; int fa[Max], f[Max], n, a, b; void init(){ for(int i = 0; i <= n + 1; i++){ //注意初始化的范围0~n+1 fa[i] = i; } } /* int find(int x){ int i = x; while(i != fa[i]){ i = fa[i]; } int j = x; while(fa[j] != i){ //数据压缩 int k = fa[j]; fa[j] = i; j = k; } return i; } */ int find(int x){ if(fa[x] == x) return x; else return fa[x] = find(fa[x]); //也压缩了,更简洁 } void Union(int x, int y){ int i = find(x); int j = find(y); if(i != j){ fa[i] = j; } } int main(){ cin >> n >> a >>b; int mymax = -1; for(int i = 1; i <= n; i++){ cin >> f[i]; mp[f[i]] = i; mymax = max(mymax, f[i]); } if(mymax > max(a, b)){ cout << "NO" << endl; } else{ init(); for(int i = 1; i <= n; i++){ if(mp[b - f[i]]) //如果b-f[i]存在 Union(i, mp[b - f[i]]); //b-f[i]存在就i和b-f[i]的映射放在一个集合里面 else Union(i, 0); //不存在是就只能讲i放入到0集合即(a集合) if(mp[a - f[i]]) Union(i, mp[a - f[i]]); else Union(i, n + 1); } int f1 = find(0); int f2 = find(n + 1); if(f1 == f2){ //一个数两个集合里都必须有,产生矛盾 cout << "NO" << endl; } else{ cout << "YES" << endl; for(int i = 1; i <= n; i++){ if(i != 1) cout << " "; if(find(i) == f1){ //f[i]的映射和0在同一个集合,这输出0,表示在A集合 cout << 0; } else cout << 1; } cout << endl; } } return 0; } /* 可以手动走一遍: 6 5 9 2 3 4 5 1 8 */