1 条题解
-
0
Missing Subsequence Sum 详细题解
这是一道构造题,核心思路是利用二进制子集和性质( 能凑出所有数),通过微小修改,恰好让 无法凑出,其余 全部能凑出,且序列长度不超过 ,完全满足题目限制。
一、关键观察(题眼)
1. 固定 时,能解决 的序列,一定能解决所有 。因此我们直接把 视作最大值 构造即可,无需关心输入的 。 2. 标准二进制序列 :
- 长度仅 ,满足 的限制;
- 子集和能恰好凑出 (覆盖 );
- 这是我们构造的基础。
二、构造方案(标程核心)
步骤1:计算关键指数
找到最大的整数 ,满足:
步骤2:生成最终序列
序列总长度不超过22,远小于题目限制 ,格式如下:
$$a = \left[\ k-2^i,\ k+1,\ k+1+2^i,\ 1,2,4,\dots,2^{i-1},\ 2^{i+1},\dots,2^{19}\ \right] $$拆解序列组成:
- 特殊数1:
- 特殊数2:
- 特殊数3:
- 二进制基础段:(缺少 )
- 二进制高位段:
三、正确性证明
1. 证明:没有子集和等于
只有数值 的元素能参与凑出 ,这些元素是:
计算它们的总和:
这些数的最大子集和为 ,永远无法凑出 ,满足第一个条件。
2. 证明:所有 都能凑出
分三类情况讨论:
情况1:
直接用二进制段 ,二进制分解即可凑出 。
情况2:
- 先取所有 的元素,和为 ;
- 需要减掉的数值:;
- 因为 ,所以 ;
- 用二进制段去掉 对应的元素,最终和为 。
情况3:
- 优先选 ,剩余需要凑:;
- 用二进制序列凑剩余值;
- 边界:若 包含 位,替换为 即可。
综上,所有非 的数都能凑出。
四、代码实现(C++)
实现逻辑
- 预处理二进制幂次 ;
- 对每组 ,计算最大的 满足 ;
- 按构造规则生成序列,直接输出。
#include <iostream> #include <vector> using namespace std; // 预处理 2^0 ~ 2^19,足够覆盖 1e6 long long p[25]; void prework() { p[0] = 1; for (int i = 1; i <= 19; ++i) p[i] = p[i-1] * 2; } int main() { ios::sync_with_stdio(false); cin.tie(0); prework(); int t; cin >> t; while (t--) { int n, k; cin >> n >> k; // 找到最大的 i 满足 2^i <= k int i = 0; while (p[i+1] <= k) i++; vector<long long> ans; // 加入三个特殊元素 ans.push_back(k - p[i]); ans.push_back(k + 1); ans.push_back(k + 1 + p[i]); // 加入 1,2,...,2^(i-1) for (int j = 0; j < i; ++j) ans.push_back(p[j]); // 加入 2^(i+1) ... 2^19 for (int j = i+1; j <= 19; ++j) ans.push_back(p[j]); // 输出 cout << ans.size() << '\n'; for (auto x : ans) cout << x << ' '; cout << '\n'; } return 0; }
五、复杂度分析
- 预处理:;
- 每组测试用例: 生成序列;
- 序列长度:固定 ,完美满足题目 的限制。
六、样例验证
以输入
9 3为例:- ,最大 ();
- 特殊数:;
- 二进制段:(),跳过 ,加入 ;
- 最终序列:,和样例输出一致,能凑出 除 外的所有数。
总结
- 核心工具:二进制子集和( 凑所有数);
- 构造关键:用 让最大子集和变为 ,恰好无法凑出 ;
- 合规性:序列长度 ,满足题目所有限制;
- 通用性:一次构造,适配所有 。
- 1
信息
- ID
- 6544
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者