1 条题解

  • 0
    @ 2025-10-17 18:35:00

    题解

    核心思路是把“左右抽屉中存在某个颜色的手套同时被取走”转化为 Pigeonhole 思维。若某个颜色只在一侧出现(另一侧数量为 0),那一侧的所有手套都必须拿走,否则永远不可能凑成这一颜色的配对——代码用 rebu_a/rebu_b 事先统计这些必取数量,并把对应颜色剔除。

    对剩余颜色,假设我们决定取走其中一部分颜色的所有左手手套,并把其它颜色交给右手抽屉负责。若我们从左边取走集合 SS 的全部手套,那么只要右边保证至少有一个颜色来自 SS,就能配对;若 SS 并非全部颜色,还需要在左边额外多拿 1 只手套以跨过抽屉边界的“安全线”。右边也有完全对称的考虑:若右侧负责集合 TT 的全部颜色,当 TT 不是全集时,也要再加 1。

    因此可以枚举剩余颜色的所有划分。程序把每个子集对应的“左侧总数 lef”与“其余颜色右侧总数 rig”记录下来,按 lef 递减排序,并用扫描的方式维护当前遇到的最大 rig。对每个候选子集 SS(记录为 lef)与之前扫描到的最佳对向集合(记录为 ma),尝试更新答案:左边需取 lef + (lef != Sum_a),右边需取 ma + (ma != Sum_b)。二者之和即当下策略的总手套数。

    历遍所有子集即可得到最小的左右抽屉取值,再把之前剔除的必取手套加回去就是最终答案。由于有效颜色最多 20 种,暴力子集的复杂度为 O(2nn)O(2^n n),完全可行。

    /*
        Trần Duy Vũ - THPT Chuyên Lương Thế Vinh
    */
    #include<bits/stdc++.h>
    using namespace std;
    using namespace chrono;
    using ll = long long;
    
    template <class X, class Y>
    void ckmin(X &x, const Y &y) { if (x > y) x = y;}
    template <class X, class Y>
    void ckmax(X &x, const Y &y) { if (x < y) x = y;}
    
    #define Duy_vu_dep_trai int main
    Duy_vu_dep_trai() {
        ios_base::sync_with_stdio(false);
        cin.tie(nullptr);
    
        int n; cin >> n;
        vector<int> a(n), b(n);
        for (int i= 0; i< n; i++) {
            cin >> a[i];
        }
        for (int i= 0; i< n; i++) {
            cin >> b[i];
        }
        int Sum_a= 0, Sum_b= 0, rebu_a= 0, rebu_b= 0;
        for (int i= 0; i< n; i++) {
            if(!a[i] || !b[i]) {
                rebu_a+= a[i];
                rebu_b+= b[i];
                swap(a[i], a[n - 1]);
                swap(b[i], b[n - 1]);
                n --;
                i--;
            }
            else {
                Sum_a+= a[i];
                Sum_b+= b[i];
            }
        }
        a.resize(n);
        b.resize(n);
        vector<pair<ll, ll>> pairs;
        for (int m1= 0; m1 < (1<< n); m1++) {
            int lef= 0, rig= 0;
            for(int i= 0; i< n; i++) {
                if(m1>>i & 1) {
                    lef+= a[i];
                }
                else {
                    rig+= b[i];
                }
            }
            pairs.push_back(make_pair(lef, rig));
        }
        sort(pairs.begin(), pairs.end());
        reverse(pairs.begin(), pairs.end());
        int ma= 0, Answers_a=1e9, Answers_b=1e9;
        for (int i= 0; i< pairs.size(); i++) {
            int x=pairs[i].first, y=pairs[i].second;
            if(x+ (x!= Sum_a) + ma + (ma!= Sum_b) < Answers_a+ Answers_b) {
                Answers_a= x+ (x!= Sum_a);
                Answers_b= ma + (ma!= Sum_b);
            }
            ckmax(ma, y);
        }
        cout<<Answers_a+rebu_a <<"\n" <<Answers_b+rebu_b <<endl;
    }
    
    • 1

    信息

    ID
    3241
    时间
    1000ms
    内存
    256MiB
    难度
    6
    标签
    递交数
    1
    已通过
    1
    上传者