题解:CF1163E Magical Permutation

· · 题解

很少在 duel 的时候遇到惊艳我的 2400 了。正好把我不熟的整合了一下。

|S| 最小是 x。考虑 S=\{0,1,2,\cdots ,2^{x-1}\}。然后我们 0,1,3,2,\cdots 构造序列。容易证明 |S| 不可能更小。

一点要注意的是,0,1,3,2,\cdots 是格雷码。

其实也就是 S 中的集合能不能表示所有 0\sim 2^x-1,并且不重不漏。

一个显然的条件是 S 中有用的数插入线性基中,线性基大小 =x

然后发现这个是冲要条件:

那么构造也简单了:可以直接暴力搜索,一定有答案。

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 4e5+5;

int n,a[N],b[20],c[20],cnt,mx;

void ins(ll x){
    ll y=x;
    for (int i=19; i>=0; i--){
        if (x>>i&1){
            if (!b[i]){
                b[i]=x;
                c[i]=y;
                cnt++;
                return;
            }
            else{
                x^=b[i];
            }
        } 
    } 
}

int vis[N];

void dfs(int u){
    cout<<u<<" ";
    vis[u]=1;
    for (int i=0; i<mx; i++){
        if (!vis[c[i]^u]){
            dfs(c[i]^u);
        }
    }
}

int main(){
    ios::sync_with_stdio(false);
    cin.tie(0);

    cin>>n;
    for (int i=1; i<=n; i++){
        cin>>a[i];
    }
    for (int i=19; i>=0; i--){
        cnt=0;
        for (int j=0; j<20; j++) b[j]=c[j]=0;
        for (int j=1; j<=n; j++){
            if (a[j]<=(1<<i)-1){
                ins(a[j]);
            }
        }
        if (cnt==i){
            mx=i;
            cout<<i<<"\n";
            dfs(0);
            return 0;
        }
    }
    return 0;
}