1 条题解
-
0
CF1988C Increasing Sequence with Fixed OR 题解
题意简述
给定正整数 ,要求构造一个严格递增的整数序列 ,满足:
- ;
- 对于所有 ,有 (按位或)。
求序列的最大长度 ,并输出任意一个最长序列。,多组数据,序列总长度 。
核心观察:按位或的约束
条件 意味着:对于 的二进制表示中每一个为 的位, 和 中至少有一个在该位上为 ;而对于 中为 的位,两者必须都为 。
换言之,所有 的二进制表示必须是 的子集(即 ),且相邻两项必须共同覆盖 中所有的 位。
构造最长序列
由于 是 的子集,且序列需严格递增,我们可以从高位到低位消去 来依次生成前驱。
具体方法
- 令最后一个元素 (显然最大)。
- 每次选取当前 中最低位的一个 ,将它变为 ,得到一个新的数作为前一个元素。
- 重复直至数字变为 ,结束。
例如 :
步骤 当前值 消去最低位 得到 1 2 3 4 5 —— 停止 倒序输出即为:。
为什么这样是最长的?
设 的二进制中 的个数为 。每个 都是 的子集(即位 的集合是 中 的子集)。
考虑序列的二进制包含关系:由于 (严格递增),且 ,这意味着 必须比 “多出”某些 位(至少一个)。而所有 位的总数只有 个,因此序列长度不可能超过 (包括 本身)。
上述构造方法恰好每步消去一个 ,序列长度达到 ,故为最长。
Lowbit 实现
利用
lowbit(x) = x & -x提取最低位的 ,循环消去即可。时间复杂度:,空间 。
参考代码
#include <bits/stdc++.h> using namespace std; using ll = long long; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int T; cin >> T; while (T--) { ll n; cin >> n; vector<ll> ans = {n}; for (ll m = n; m; ) { ll t = m & -m; // lowbit m -= t; if (n - t > 0) ans.push_back(n - t); } // ans 中存储的是从大到小的顺序,需要逆序输出 reverse(ans.begin(), ans.end()); cout << ans.size() << '\n'; for (ll x : ans) cout << x << ' '; cout << '\n'; } return 0; }
- 1
信息
- ID
- 6823
- 时间
- 3000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者