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;
}
posted @ 2024-04-28 12:02  Creeper_l  阅读(127)  评论(0编辑  收藏  举报