VIRTUALS

the virtual labs for the virtuals

0%

AcWing 2767.优秀的拆分 [2020 CCF CSP-J2, NOIP]

摘要:
2020 CCF CSP-J2普及组 aka NOIP

题目

一般来说,一个正整数可以拆分成若干个正整数的和。
例如,$1=1$,$10=1+2+3+4$ 等。
对于正整数 $n$ 的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,$n$ 被分解为了若干个 不同 的 $2$ 的 正整数 次幂。
注意,一个数 $x$ 能被表示成 $2$ 的正整数次幂,当且仅当 $x$ 能通过正整数个 $2$ 相乘在一起得到。
例如,$10=8+2=2^3+2^1$ 是一个优秀的拆分。
但是,$7=4+2+1=2^2+2^1+2^0$ 就不是一个优秀的拆分,因为 $1$ 不是 $2$ 的正整数次幂。
现在,给定正整数 $n$,你需要判断这个数的所有拆分中,是否存在优秀的拆分。
若存在,请你给出具体的拆分方案。
本题暂时采用AcWing数据。

输入格式
输入文件只有一行,一个正整数 n,代表需要判断的数。

输出格式
如果这个数的所有拆分中,存在优秀的拆分。
那么,你需要 从大到小 输出这个拆分中的每一个数,相邻两个数之间用一个空格隔开。
可以证明,在规定了拆分数字的顺序后,该拆分方案是 唯一 的。
若不存在优秀的拆分,输出 “-1”(不包含双引号)。

数据范围
对于 $20\%$ 的数据,$n≤10$。
对于另外 $20\%$ 的数据,保证 $n$ 为奇数。
对于另外 $20\%$ 的数据,保证 $n$ 为 $2$ 的正整数次幂。
对于 $80\%$ 的数据,$n≤1024$。
对于 $100\%$ 的数据,$1≤n≤1×10^7$。

输入样例1:

6

输出样例1:

4 2

样例1解释
$6=4+2=2^2+2^1$ 是一个优秀的拆分。

注意,$6=2+2+2$ 不是一个优秀的拆分,因为拆分成的 $3$ 个数不满足每个数互不相同。

输入样例2:

7

输出样例2:

-1


本质是考二进制。一个奇数不可能存在优秀的拆分;偶数一定存在优秀的拆分。偶数的优秀拆分可表示成其二进制数转十进制时,底数2的次幂。
如:
十进制10的二进制为1010,转化为十进制即 $2^3 + 2^1$ 。那么10的优秀拆分就是 8 2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <iostream>

using namespace std;

int main()
{
int n;
cin >> n;
if (n % 2) cout << -1; // 1
else {
for (int i = 23; i >= 0; i --) { // 2
if (n >> i & 1) { // 3
printf("%d ", 1 << i); // 4
}
}
}
return 0;
}
  1. 奇数不存在优秀拆分。
  2. 题目限制 n <= 1e7,所以n的二进制数最高位1最高可取到第23位(从0开始)。
  3. 判断从二进制最低位起第i位是否为1。
  4. 输出第i位为1的十进制数字,可以看成是该位右边全为0时的十进制数,等价于将1左移i位。

我觉得本题重点是能想到用二进制来表示数字,另外就是对数字范围的判断。

原题链接:

AcWing 2767.优秀的拆分