CF1966D Missing Subsequence Sum 题解
题意:给定 \(n(n \le 10^6)\) 和 \(k(k \le n)\)。构造一个长度小于等于 \(25\) 的序列 \(a\) 满足:
1. 不存在一个子序列的和为 \(k\)。
2. 对于 \(1 \le i \le n,i \ne k\),存在一个子序列的和为 \(i\)。
看到长度为 \(25\),首先肯定会想到二进制。那么我们先构造出一个序列 \([2^0,2^1,\dots,2^{19}]\),会发现这样一定可以表示出所有 \(1\) 到 \(n\) 的数。但是要求不能表示出 \(k\),所以我们把 \(2^p\) 删掉,其中 \(p\) 是 \(k\) 的最高位,这样就一定表示不出 \(k\) 了。
删掉之后会出现一个问题,除了 \(k\) 之外第 \(p\) 位为 \(1\) 的数也不能表示出来了,考虑如何解决。
一个结论是:再加上 \(k-2^p,k+1,k+1+2^p\) 这三个数,最终的序列一定合法。
\(\text{Prove}\):
- \(1 \le i \le k-2_p\)
因为 \(k - 2_p \le 2^{p}-1\),所以直接用 \([2^0,2^1,\dots,2^{p-1}]\) 表示即可。 - \(k-2^{p} < i \le k-1\)
先将 \(i\) 减去 \(k-2^{p}\),因为 \(i-(k-2_p) \le 2^{p}-1\),所以剩下的直接用 \([2^0,2^1,\dots,2^{p-1}]\) 表示即可。 - \(i=k\)
所有小于等于 \(k\) 的数的和才 \(k-1\),显然表示不出 \(k\)。 - \(k+1 \le i \le n\)
先将 \(i\) 减去 \(k+1\),如果减完之后 \(i\) 的第 \(p\) 位是 \(1\) 的话就改为减 \(k+1+2^p\)。这样减完之后的 \(i\) 的第 \(p\) 位一定为 \(0\),所以一定能表示出来。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int T,n,k,ans[100];
signed main() {
cin >> T;
while(T--) {
cin >> n >> k;
int p = __lg(k),tot = 0;
for(int i = 0;i <= 19;i++)
if(i != p) ans[++tot] = (1ll << i);
ans[++tot] = k - (1ll << p);
ans[++tot] = k + 1;
ans[++tot] = k + 1 + (1ll << p);
cout << tot << endl;
for(int i = 1;i <= tot;i++)
cout << ans[i] << " ";
cout << endl;
}
return 0;
}
本文作者:Creeper_l
本文链接:https://www.cnblogs.com/Creeperl/p/18163441
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】博客园2025新款「AI繁忙」系列T恤上架,前往周边小店选购
【推荐】凌霞软件回馈社区,携手博客园推出1Panel与Halo联合会员
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步