2026牛客暑期多校2 H 题思路分享(构造)

题意

对于 \(n\) 维超立方体,删掉 \(a,b\) 两点,构造一种方案使得剩余点两两配对,满足配对的点二进制中恰好有两位不同.

\(2\le n \le 22\).

思路

配对点有两位不同,即 \(popcount\) 奇偶性相同,因此必须满足 \(popcount(a) \equiv popcount(b) \pmod 2\),否则奇点和偶点均有奇数个元素.

\(a\)\(b\) 某个不同位为 \(c\),将所有数 \(c\) 位删掉后,\(popcount(a')\not\equiv popcount(b') \pmod 2\),于是可以找一条在 \(n-1\) 维超立方体中,\(a'\)\(b'\) 的哈密顿路径,记为 \(P\).

我们想要在原超立方体中,\(popcount\) 全奇和全偶的两条路径,可以自由地将 \(1\)\(0\) 重新插入 \(P\) 每个元素第 \(c\) 位,保证路径所有元素奇偶性一致即可,显然地,构造两条路径所有插入的值都是确定的,并且并集为 \([0\cdots 2^n-1]\).

时间复杂度 \(\mathcal{O}(2^n)\).

代码

//author:kzssCCC

#include <bits/stdc++.h>
using namespace std;
using ll = long long;

int erase(int x,int k){
    int low = x&((1<<k)-1);
    int high = x>>k+1<<k;
    return high|low;
}

int insert(int x,int k,int bit){
    int low = x&((1<<k)-1);
    int high = x>>k<<k;
    return (high<<1)|(bit<<k)|low;
}

void solve(){
    int n,a,b;
    cin >> n >> a >> b;

    if ((__builtin_popcount(a)&1)!=(__builtin_popcount(b)&1)){
        cout << "NO" << '\n';
        return;
    }
    cout << "YES" << '\n';

    int k = __builtin_ctz(a^b);
    int s = erase(a,k);
    int t = erase(b,k);

    vector<int> res(1<<n-1);
    function<void(int,int,int,int,int)> dfs = [&](int mask,int s,int t,int l,int r){
        if (r==l+1){
            res[l] = s;
            res[r] = t;
            return;
        } 

        int mid = l+r >> 1;
        int c = __builtin_ctz((s^t)&mask);
        int nmask = mask^(1<<c);
        int j = __builtin_ctz(nmask);
        int x = s^(1<<j);
        int y = x^(1<<c);
        dfs(nmask,s,x,l,mid);
        dfs(nmask,y,t,mid+1,r);
    };
    dfs((1<<n-1)-1,s,t,0,(1<<n-1)-1);

    vector<int> res1(1<<n-1),res2(1<<n-1);
    for (int i=0;i<1<<n-1;i++){
        res1[i] = insert(res[i],k,(__builtin_popcount(res[i])&1)^1);        
    }
    for (int i=0;i<1<<n-1;i++){
        res2[i] = insert(res[i],k,(__builtin_popcount(res[i])&1));        
    }

    if (__builtin_popcount(a)&1){
        for (int i=1;i<(1<<n-1)-1;i+=2){
            cout << res1[i] << ' ' << res1[i+1] << '\n';
        }    
        for (int i=0;i<1<<n-1;i+=2){
            cout << res2[i] << ' ' << res2[i+1] << '\n';
        }
    }   
    else{
        for (int i=1;i<(1<<n-1)-1;i+=2){
            cout << res2[i] << ' ' << res2[i+1] << '\n';
        }    
        for (int i=0;i<1<<n-1;i+=2){
            cout << res1[i] << ' ' << res1[i+1] << '\n';
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);
    
    int t = 1;
    cin >> t;
    while (t--) solve();

    return 0;
}
posted @ 2026-07-25 16:15  kzssCCC  阅读(10)  评论(0)    收藏  举报