其他分享
首页 > 其他分享> > cf468 B. Two Sets

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