个人主页:
专题分栏:洛谷刷题
题目链接:P1010 [NOIP1998 普及组] 幂次方 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
目录
第一步:任何一个正整数都可以用 2 的幂次方表示。根据示例137=2^7+2^3+2^0。我们也同样,先把正整数拆开成上述格式。
一、题目
题目描述
任何一个正整数都可以用 2 的幂次方表示。例如 137=2^7+2^3+2^0。
同时约定方次用括号来表示,即a^b 可表示为 a(b)。
由此可知,137 可表示为 2(7)+2(3)+2(0)
进一步:
7=2^2+2+2^0 ( 2^1 用 2 表示),并且 3=2+2^0。
所以最后 137 可表示为 2(2(2)+2+2(0))+2(2+2(0))+2(0)2(2(2)+2+2(0))+2(2+2(0))+2(0)。
又如 1315=2^10+2^8+2^5+2+1
所以 1315 最后可表示为 2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)。
输入格式
一行一个正整数 n。
输出格式
符合约定的 n 的 0,2 表示(在表示中不能有空格)。
输入输出样例
输入 输出
1315 2(2(2+2(0))+2)+2(2(2+2(0)))+2(2(2)+2(0))+2+2(0)说明/提示
【数据范围】
对于 100% 的数据,1≤n≤2×10^4。
二、题解
1.老规矩,还是先对题目进行分析:
这个题目比较简洁,题目内容比较简单。要注意的就是2^1用2表示,不需要写括号,1用2(0)表示。
2.代码的逐步编写:
第一步:任何一个正整数都可以用 2 的幂次方表示。根据示例137=2^7+2^3+2^0。我们也同样,先把正整数拆开成上述格式。
#include<stdio.h>
#include<math.h>
int main()
{
int n;
scanf("%d", &n);//所求的数
int flag = n % 2;//奇偶数标记:判断一下奇偶数
while (n)//把n逐层的拆开
{
int i = 0;
while (n >= (int)pow(2, i))//寻找一下比n大的最小2的次幂数,i为最小2的次幂数的指数
i++;
//判断结束标志
if ((n - (int)pow(2, i - 1) == 0) || (flag == 1 && i - 1 == 0))//i-1为在1~n的范围内最大2的次幂数,因为pow函数默认的是double类型,而n为整型,所以将pow强制类型转化
{
if (i - 1 > 1)
{
printf("2(%d)", i - 1);
}
else if (i - 1 == 1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
else
{
if (i - 1 > 1)
{
printf("2(%d)+", i - 1);
}
else if (i - 1 == 1)
{
printf("2+");
}
else
{
printf("2(0)+");
}
}
n -= (int)pow(2, i - 1);//把最大的2的次幂数减掉,得到剩余的数,然后再进行上述步骤进行分割
}
return 0;
}
运行结果=============================
如果没有下面的条件语句的话,会出现bug
if ((n - (int)pow(2, i - 1) == 0) || (flag == 1 && i - 1 == 0))
因为137=2^7+2^3+2^0是用’+‘相连的
如果代码只有else部分:最后还会出现’+‘,这是不必要的,所以需要判断什么时候是最后一个2的次幂方数。
而根据思考,当剩余的数正好是2的次幂方的时候,或者如果剩余的数正好是1的时候,没有办法继续往下分,所以条件就是把上述的话编译成代码即可。
第二步:如何将括号里面的数也转化为关于2的次幂方之和
现在的运行结果里最终答案已经接近了。
此时,我们为了简便main函数里面的代码量,我选择用函数的方式,完成这项功能。
和前面一样,像把大的数化简为2的次幂方之和的数一样,我们也用相同的思维,来完成函数
在代码编写前,我们需要确定函数的名称,参数,返回值。名称我就用test01来编写(用其他的也行,这个没有什么要求)。参数,我们需要的是将括号里面2的次幂转化成0,2格式,所以,我们不妨用括号里面的数当作参数(137=2(7)+2(3)+2(0),就比如这里的7,3)。返回值,我们只需要打印,所以就直接用void类型。
void test01(int n)
{
if (n > 1)//首先,他本来就是次幂,所以,我们需要一开始就对其进行判断,如果不判断的话就会出现2(1)这中情况的出现
{
//下面大体和main函数里面的一样
int flag = n % 2;
while (n)
{
int i = 0;
while (n >= (int)pow(2, i))
i++;
if ((n-(int)pow(2,i-1)==0 ) || (flag == 1 && i - 1 == 0))
{
if (i - 1 > 1)
{
printf("2(");
test01(i - 1);//这里采用递归的方式,防止拆一次拆不彻底,就比如n=8,第一次拆会出现2(3),而3也能进行下次的拆分
printf(")");
}
else if (i - 1 == 1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
else
{
if (i - 1 > 1)
{
printf("2(");
test01(i - 1);
printf(")+");
}
else if (i - 1 == 1)
{
printf("2+");
}
else
{
printf("2(0)+");
}
}
n -= (int)pow(2, i - 1);
}
}
else if(n==1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
最后:合并
主要的步骤都已经弄完了,只需要把上述两部分合并即可。
#include<stdio.h>
#include<math.h>
void test01(int n);//函数声明
int main()
{
int n;
scanf("%d", &n);
int flag = n % 2;
while (n)
{
int i = 0;
while (n>=(int)pow(2,i))
i++;
if ((n - (int)pow(2, i - 1) == 0) || (flag == 1 && i - 1 == 0))
{
if (i-1 > 1)
{
printf("2(");
test01(i - 1);对函数的调用
printf(")");
}
else if(i-1 == 1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
else
{
if (i - 1 > 1)
{
printf("2(");
test01(i - 1);
printf(")+");
}
else if (i - 1 == 1)
{
printf("2+");
}
else
{
printf("2(0)+");
}
}
n -= (int)pow(2, i - 1);
}
return 0;
}
void test01(int n)
{
if (n > 1)
{
int flag = n % 2;
while (n)
{
int i = 0;
while (n >= (int)pow(2, i))
i++;
if ((/*0 == flag*/n-(int)pow(2,i-1)==0 ) || (flag == 1 && i - 1 == 0))
{
if (i - 1 > 1)
{
printf("2(");
test01(i - 1);
printf(")");
}
else if (i - 1 == 1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
else
{
//printf("2(%d)+", i - 1);
if (i - 1 > 1)
{
printf("2(");
test01(i - 1);
printf(")+");
}
else if (i - 1 == 1)
{
printf("2+");
}
else
{
printf("2(0)+");
}
}
n -= (int)pow(2, i - 1);
}
}
else if(n==1)
{
printf("2");
}
else
{
printf("2(0)");
}
}
3.运行结果
谢谢大家支持!!!
让我们共同进步。