CF Round 1006 (Div. 3) Problem C 题解
题目传送门
萌新第一次写题解, 表达不清请见谅, 本篇题解是想把本人做题时的想法整理下来, 更优秀的题解请移步CF。
本题涉及到 \(MEX\) (在一个整数集合中从 \(0\) 开始第一个没出现的整数), 这种题一般用贪心的方法得到 \(MEX\) 的最大值, 本题也是如此。
分析题目可以得到这样的结论,最终输出的数列可以是从 \(0\) 一直到某个数 \(k\) ,然后在数列的末尾再加上 \(x\) ,但是如果之前的数列进行或运算( \(a|b\) )后已经满足条件,就不用加 \(x\)。
这样问题的关键就转换为 \(k\) 是多少, 先考虑 \(n\) 足够大的情况, 对于给定的 \(x\), 把它转换为二进制后, 每一个 \(0\) 位都像是把这一位给占住了, 要输出的数列中的任何一个数转换为二进制后被占住的位都不能是 \(1\), 否则或运算后一定不等于 \(x\)。 顺着这个思路想, 就很容易得到 \(k\) 是怎么算出来的: \(k\) 就是 \(x\) 最低位 \(0\) 之前的 \(1\) 组成的二进制数。 例如,当 \(x = 111011011\) 时, \(k = 11\)。 别忘了现在是在讨论 \(n\) 足够大的情况。
为了避免混淆, 将以上方法求出的 \(k\) 记为 \(k_{max}\)。 当 \(n - 1> k_{max}+1\) 时(为什么是这个条件, 这一点请仔细思考), 前面从 \(0\) 到 \(k_{max}\) 全都占满了, 一共 \(k_{max}+1\) 个数, 数组剩下的长度可以全都填 \(x\)。 再考虑 \(n - 1 \le k_{max}+1\) 的情况, 先对从 \(0\) 到 \(n-1\), 长度为 \(n\) 的数组进行或运算, 如果结果等于 \(x\), 则答案就是从 \(0\) 到 \(n-1\) 数组, 如果不等于 \(x\), 则答案是从 \(0\) 到 \(n-2\) 末尾加上 \(x\)。
下面贴上AC代码:
#include <bits/stdc++.h>
using namespace std;void solve(){int n,x;cin >> n >> x;int k=0,cx=1,xc = x;while(x&1){k+=cx;cx*=2;x/=2;}if(n-1>k+1){for(int i=0;i<n;i++){if(i<k+1) cout << i << ' ';else cout << xc << ' ';}}else{int ans = 0;for(int i=0;i<=n-2;i++){cout << i << ' ';ans |= i;}if((ans|(n-1))==xc) cout << n-1;else cout << xc;}cout << endl;
}int main(){int t = 1;cin >> t;while(t--){solve();}
}