2 条题解
-
0
#include <bits/stdc++.h> using namespace std; int main(){ int n; cin>>n; //思路:根据位值原理,题目意思是原数的二进制最右位不能是1,然后输出位为1的数位 if(n%2!=0){ cout<<"-1"<<endl; return 0; } //是偶数 int nowbit=2;//当前循环位值 n=n/2; vector<int> ans=vector<int>();//用动态数组vector做容器,方便逆序输出 while(n>0){ if(n%2==1){//二进制里取末位的方法是mod2 ans.push_back(nowbit); } n=n/2; nowbit=nowbit*2; } for(int i=ans.size()-1;i>=0;i--){ cout<<ans[i]; if(i!=0){//最后一个数字不要输出空格 cout<<" "; } } } -
0
P7071 这道题(CSP-J 2020 T1)考察的是对二进制和位运算的理解。虽然题目包装了一个“优秀的拆分”的概念,但剥开外壳,本质上非常数学。
下面我给你提供几个关键的突破口:
1. 审题:什么叫“优秀的拆分”?
题目有两个硬性条件:
- 拆分成 的正整数次幂。
- 这些数必须 互不相同。
我们来分析一下:
- 的正整数次幂:指的是 ,也就是 。
- 注意! 不是正整数次幂(0不是正整数)。这意味着拆分里不能包含 1。
- 互不相同:这让你想到了什么?对了,这就是二进制的定义!任何一个正整数都可以唯一地表示为二进制形式(即若干个不同的 2 的幂之和)。
2. 第一步:判断无解情况 (-1)
根据上面的分析,唯一的限制就是不能有 (也就是 1)。
- 在二进制表示中,最低位(最右边一位)代表 。
- 如果一个数的二进制最低位是
1,说明这个数包含 ,它就是一个奇数。 - 如果一个数的二进制最低位是
0,说明这个数不包含 ,它就是一个偶数。
结论:
- 如果是奇数,它一定包含 ,不满足“优秀的拆分”,直接输出
-1。 - 如果是偶数,它一定能被拆分为 的和,一定有解。
3. 第二步:如何拆分并从大到小输出?
题目要求从大到小输出。这其实是提示我们要从高位向低位检查。
对于 ,最大的 的幂次不会超过 (因为 $2^{10} \approx 1000, 2^{20} \approx 100W, 2^{24} \approx 1600W$)。
解法一:贪心(数学思维) 你可以准备一个循环,从 的某个高次幂开始(比如 ),试探能不能“装”进 里。
- 如果当前幂次 ,说明 里包含这个 。输出 ,然后 减去 。
- 继续试探下一个更小的幂次。
解法二:位运算(更像程序员的思维) 直接检查 的二进制每一位。
- 使用一个循环,变量
i从大到小(比如从 24 循环到 1)。 - 检查 的第
i位是否为 1。 - 如果是 1,说明这一位代表的数值是 ,输出它。
- 提示:如何计算 ?可以用
1 << i。如何检查第 i 位?可以用n & (1 << i)。
4. 代码框架提示
#include <iostream> #include <cmath> // 或者用位运算代替 pow using namespace std; int main() { int n; cin >> n; // 1. 判断奇偶性 if (n % 2 != 0) { cout << -1 << endl; return 0; } // 2. 从大到小枚举 2 的幂 // 10^7 大约是 2 的 23-24 次方左右,所以从 24 开始向下枚举足够了 // 注意题目要求正整数次幂,所以循环只到 1,不到 0 for (int i = 24; i >= 1; i--) { // 计算 2 的 i 次方 int power = (1 << i); // 这里的 << 是左移运算符,1 << i 等于 2^i // 3. 判断 n 是否包含这个幂 // 方法A: 简单的减法逻辑 if (n >= power) { cout << power << " "; n -= power; } // 方法B: 位运算逻辑 // if ((n & power) == power) { ... } } return 0; }这道题其实就是让你手动实现一个“十进制转二进制”的过程,只是跳过了 这一位。只要思路通了,代码非常短!加油!
- 1
信息
- ID
- 3824
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 4
- 已通过
- 4
- 上传者