题目描述
自幂数是指,一个 N 位数,满足各位数字 N 次方之和是本身。例如,153 是 3 位数,其每位数的 3 次方之和,1^3+ +5^3+3 ^3 =153,因此 153 是自幂数;1634 是 4 位数,其每位数的 4 次方之和,1 ^4+6 ^4+3 ^4+4^4 =1634,因此 1634 是自幂数。现在,输入若干个正整数,请判断它们是否是自幂数。
输入格式
输入第一行是一个正整数 M,表示有 M 个待判断的正整数。约定 1≤M≤100。
从第 2 行开始的 M 行,每行一个待判断的正整数。约定这些正整数均小于 10 ^8 。
输出格式
输出 M 行,如果对应的待判断正整数为自幂数,则输出英文大写字母 T,否则输出英文大写字母 F。
提示:不需要等到所有输入结束在依次输出,可以输入一个数就判断一个数并输出,再输入下一个数。
输入输出样例
B3841 [GESP202306 二级] 自幂数判断 - 洛谷 https://www.luogu.com.cn/problem/B3841
基础思路分析
关键步骤
- 确定数字位数N:通过不断除以10计算数字的位数
- 计算各位数字的N次方和:分离各位数字并计算其N次方之和
- 比较判断:检查和是否等于原数字
常见错误点
- 原始数字被破坏:在计算过程中修改了原始数字
- pow函数的精度问题:直接使用pow可能导致整数计算错误
- 循环控制不当:循环次数或终止条件不正确
方法一:基础实现
#include <bits/stdc++.h>
using namespace std;
int main(){
int M;cin>>M;
while(M--){
int N=0,sum=0;
int x,t;cin>>x;
t=x;
while(t){
N++;
t=t/10;
}
t=x; //此句不可少,后面的for循环不能对x直接操作,不然后面的if语句无法成立
for(int i=1;i<=N;i++){
sum+=pow(t%10,N);
t=t/10;
}
if(sum==x) cout<<'T'<<endl;
else cout<<'F'<<endl;
}
}
方法二:用函数实现
#include <bits/stdc++.h>
using namespace std;
bool func(int x){
int N=0,sum=0;
int t=x;
while(t){
N++;
t=t/10;
}
t=x;
for(int i=1;i<=N;i++){
sum+=round(pow(t%10,N);
t=t/10;
}
return sum==x;
}
int main(){
int M;cin>>M;
while(M--){
int x,t;cin>>x;
cout<<(func(x)?'T':'F')<<endl;
}
}
为什么直接使用 pow 函数可能导致整数计算错误?
pow 函数在大多数标准库中的实现是基于浮点数运算的,它返回的是 double 类型。
pow 定义在 <cmath> 里,原型是:
double pow(double base, double exp);
当我们这样使用时:
int result = pow(5, 3); // 期望125
实际上发生了:
计算浮点数结果 pow(5.0, 3.0)
将结果转换为整数(截断小数部分)
具体问题表现
案例1:简单立方计算
int a = pow(5, 3); // 期望125,但可能得到124
原因:
pow(5,3)
可能计算得到124.99999999999997转换为整数时截断小数部分,得到124
案例2:更大的指数
int b = pow(10, 2); // 可能得到99而不是100
案例3:边界情况
for (int i = 0; i < 10; i++) {
cout << pow(10, i) << " => " << (int)pow(10, i) << endl;
}
输出可能显示:
1 => 1
10 => 10
100 => 99
1000 => 1000
10000 => 9999
...
为什么会出现这种问题?
浮点数精度限制
- 浮点数使用二进制分数表示十进制数
- 某些十进制数无法精确表示为二进制浮点数
- 运算过程中的舍入误差会累积
实现差异
不同编译器的 pow 实现可能有差异:
- 某些实现可能对特定输入进行优化
- 不同CPU架构的浮点运算单元行为可能不同
- 编译器优化级别可能影响结果
解决方案
方法1:使用 round 函数
int result = round(pow(5, 3)); // 确保四舍五入
方法2:自定义整数幂函数
int intPow(int base, int exp) {
int result = 1;
for (int i = 0; i < exp; ++i)
result *= base;
return result;
}
方法3:预处理幂值
对于已知范围的指数,可以预先计算:
const int POW5[] = {1, 5, 25, 125, 625};
int result = POW5[3]; // 直接取用
性能考虑
结论
在需要精确整数幂运算的场合(如自幂数判断),建议:
使用 round(pow(...)) 组合
或者更好的是,实现自己的整数幂函数
对于性能关键代码,考虑查表法
理解这些底层细节对于写出健壮、可靠的数值计算代码至关重要。
方法三:避免使用pow函数(自定义整数幂函数)
#include <iostream>
using namespace std;
// 自定义整数幂函数
int intPow(int base, int exp) {
int result = 1;
for(int i = 0; i < exp; ++i) {
result *= base;
}
return result;
}
bool func(int x){
int N=0,sum=0;
int t=x;
//计算位数N
while(t){
N++;
t=t/10;
}
// 计算各位数字的N次方和
t=x;
while(t) {
sum += intPow(t%10, N); // 使用自定义幂函数
t /= 10;
}
return sum==x;
}
int main(){
int M;cin>>M;
while(M--){
int x,t;cin>>x;
cout<<(func(x)?'T':'F')<<endl;
}
}
方法四:预处理幂次结果
#include <iostream>
using namespace std;
bool func(int x) {
int N = 0, sum = 0;
// 计算位数N
int t = x;
while(t) {
N++;
t /= 10;
}
// 预处理0-9的N次方
int powers[10];
for(int i = 0; i < 10; ++i) {
int power = 1;
for(int j = 0; j < N; ++j) {
power *= i;
}
powers[i] = power;
}
// 计算各位数字的N次方和
t = x;
while(t) {
sum += powers[t % 10];
t /= 10;
}
return sum == x;
}
int main(){
int M;cin>>M;
while(M--){
int x,t;cin>>x;
cout<<(func(x)?'T':'F')<<endl;
}
}
方法五:字符串处理法
#include <bits/stdc++.h>
using namespace std;
bool func(int x) {
stringstream ss;
ss << x;
string s = ss.str();//将整数转换为字符串形式,方便获取数字的位数
//string s = to_string(x);// C++11 引入的函数,编译器版本太旧无法识别
int N = s.length();//计算数字的位数
int sum = 0;
//c依次取字符串中的每个字符
for(int i=0;i<N;i++) {
int digit = s[i] - '0';//将字符数字转换为整型数字
sum += round(pow(digit, N));
}
return sum == x;
}
int main(){
int M;cin>>M;
while(M--){
int x,t;cin>>x;
cout<<(func(x)?'T':'F')<<endl;
}
}
方法对比