cf468 B. Two Sets
作者:互联网
题意:
给定 \(n\) 个两两不同的正整数,问能否把它们不重不漏地分为两个集合 \(A,B\)。要求:
\(x\in A\implies a-x\in A\)
\(x\in B\implies b-x\in B\)
思路:
法一:很傻很暴力
先假定所有数都属于 \(A\)
检查所有数,对某数 \(x\),若 \(a-x\notin A\),则把 \(x\) 推入待处理队列 \(q\)
检查 \(q\) 中的所有数,对某数 \(x\),若 \(b-x\) 未出现过则 NO;否则把 \(x\) 和 \(b-x\) 都放入 \(B\) 中。注意要考虑这一操作有没有后续影响:
把 \(x\) 从 \(A\) 拿出:因为在 \(A\) 中与 \(x\) 配对的 \(a-x\) 不存在,所以没影响;
把 \(b-x\) 从 \(A\) 拿出:也要把 \(a-(b-x)\) 从 \(A\) 中拿出,故把它加进队列
void sol() {
int n, A, B; cin >> n >> A >> B;
vector<int> a(n); map<int, bool> inA;
for(int &x : a) cin >> x, inA[x] = true;
queue<int> q;
for(int &x : a) if(!inA[A-x]) q.push(x);
while(q.size()) {
int x = q.front(); q.pop();
if(!inA[x]) continue; //被a-x拿出来过了
if(!inA[B-x]) return cout << "NO", void();
inA[x] = inA[B-x] = false; //从A挪到B
if(inA[A-(B-x)]) q.push(A-(B-x));
}
cout << "YES\n";
for(int &x : a) cout << (!inA[x]) << ' ';
}
法二:并查集
性质:\(x,a-x,b-x\) 三者(如果存在的话)必须同属一个集合
对于某数 \(x\):
若 \(a-x,b-x\) 都不存在,NO;
若 \(a-x\) 不存在,则 \(x\) 只可能在集合 \(B\);
若 \(b-x\) 不存在,则 \(x\) 只可能在集合 \(A\);
若 \(a-x,b-x\) 都存在,则 \(x\) 与 \(a-x\) 和 \(b-x\) 在同一个集合。
开并查集维护,记 1e9+1 为集合 \(A\),1e9+2 为集合 \(B\)。最后若 \(A,B\) 连通则 NO
int n, a, b, A = 1e9+1, B = 1e9+2;
map<int, int> p; //并查集,顺便记录存在性
void sol() {
int n, a, b; cin >> n >> a >> b;
vector<int> ve(n);
for(int &x : ve) cin >> x, p[x] = x; //initDSU
p[A] = A, p[B] = B;
for(int &x : ve) {
if(p[a-x]) mer(x, a-x); else mer(x, B);
if(p[b-x]) mer(x, b-x); else mer(x, A);
}
A = get(A), B = get(B);
if(A == B) cout << "NO";
else {
cout << "YES\n";
for(int &x : ve) cout << (get(x) != A) << ' ';
}
}
标签:int,cf468,mer,Two,cin,1e9,Sets,集合,inA 来源: https://www.cnblogs.com/wushansinger/p/16368520.html