【题解】P8813 题解
2023 年 10 月 15 日更新:增加注释,修改错误的代码。感谢 hexuchen 大佬指出。
2024 年 7 月 31 日更新:没想到两年前写的题解能被这么多人看到,也非常感谢各位的支持!现在评论区中提出了一些问题,这里就这些问题统一回答,并对评论区中有价值的建议对题解进行了修改。
-
Q:方法太复杂了,没必要!
A:是的,我承认自己当时的考场做法确实较为复杂,相比其他人的做法来看,这个做法显得臃肿而多余。但是我还是想说:这也不失为一种方法。学习 OI,接受一种比较复杂的新思路也是重要的,万一后面这种思想可以被用于其它题目呢?
-
Q:判断
a^b 是否小于0 ,小于0 代表溢出。看看它溢不溢出就行了。A:请注意:带符号整数溢出在 C++ 中是未定义行为,这意味着编译器可以随意地处理这种行为,比如,编译器返回
114514 代表溢出也是可以的,所以这种做法有风险,虽不失为一种方法,但在考场上使用务必谨慎。 -
Q:特判
a 时需考虑b 是否大于1,特判b 时需考虑a 是否大于1 吗?A:不需要。请注意当
a 或b 等于1 时,根据数据范围和1^x=1 可以肯定答案不会超过10^9 。
2025 年 2 月 15 日更新:再次回看自己原来的做法(下文中的方法一)发现还是太吃操作了,于是补充了一种简单而强势的方法。上述回答针对的是第一种做法。
2025 年 3 月 6 日更新:根据评论区中的意见再次加入了一种代码量极小做法,感谢 Clovtong 大佬提出这种做法。
2025 年 4 月 27 日更新:更新了一些描述和代码,感谢 __orange__ 大佬指出这个细节问题。
P8813 题解
方法一(考场做法)
思路分析
这道题主要是特判。
首先我们发现,
但是余下的怎么办呢?显然,当
代码
#include <iostream>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
//特判
if(a == 1)
{
cout << 1 << endl;
return 0;
}
if(b == 1)
{
cout << a << endl;
return 0;
}
if(a > 31622)
{
cout << -1 << endl;
return 0;
}
if(b > 29)
{
cout << -1 << endl;
return 0;
}
long long fac = 1;
for(int i = 1;i <= b;i++) //i 表示准备乘上第 i 个 a
{
if((1e9 / double(fac)) < a) //准备乘上的时候看看是否超出限制
{
cout << -1 << endl;
return 0;
}
fac *= a;
}
cout << fac << endl;
return 0;
}
方法二(更为简洁的做法)
思路分析
考虑到
假设 long long 的范围。
于是我们直接开一个 long long 类型的变量
我们来分析一下复杂度。当
代码
#include <iostream>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
//特判
if(a == 1)
{
cout << 1 << endl;
return 0;
}
long long x = 1;
for(int i = 1;i <= b;i++) //模拟幂运算的过程
{
x *= a;
if(x > 1e9)
{
cout << -1 << endl;
return 0;
}
}
cout << x << endl;
return 0;
}
方法三(pow 函数做法)
方法概述
直接使用 pow 函数计算
正确性证明
首先我们来看时间复杂度是否正确。参考 这个问题的回答:
That depends on the underlying architecture. On the most common desktop architecture, x86, this is a constant time operation.
这取决于底层的体系结构。在最常见的桌面体系结构 x86 上,这是一个常数时间操作。
即时间复杂度为
接着我们来看正确性。双精度浮点数,即 double 类型,它的存储范围约为:
当一个数过小时,这个数会被下溢到
当一个数过大(超过储存范围)时,这个数会上溢成
同时 pow 的运算会存在严重的精度缺失问题。但是由于
于是,我们可以认为,这么做是正确的。
代码
在实现代码时需要注意,当且仅当 double 时,与
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int a, b;
cin >> a >> b;
double x = pow(a, b);
cout << int(x > 1e9 ? -1 : x) << endl;
return 0;
}