连续乘法时做上界截断;一旦超过 10^9 就输出 -1,a >= 2 时最多乘约 30 次。
OJ: luogu
题目 ID: P8813
难度:普及-
标签:数学模拟
日期: 2026-06-18 22:47
题意
给出两个正整数 a, b。
如果 -1。
思路
先看一个可以直接验证想法的朴素解:
从 1 开始,连续乘上 a 共 b 次。
每乘一次就检查当前结果是否已经超过 -1。
cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll LIMIT = 1000000000LL;
ll a, b;
void solve() {
ll ans = 1;
for (ll i = 1; i <= b; i++) {
if (ans > LIMIT / a) {
cout << -1 << '\n';
return;
}
ans *= a;
if (ans > LIMIT) {
cout << -1 << '\n';
return;
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> a >> b;
solve();
return 0;
}乍一看,题目里的 b 可以到 10^9,好像不能真的连乘这么多次。
但这里有一个更重要的条件:题目并不要求算出很大的幂。只要结果超过 -1。
如果 a = 1,那么无论 b 多大,答案都是 1。
如果 a >= 2,连续乘法增长非常快:
| 乘法次数 | 最小可能结果 |
|---|---|
| 10 次 | |
| 20 次 | |
| 30 次 |
也就是说,只要 b 本身也不会很大。
所以正式做法仍然是连续乘,只是在每次乘之前先判断是否会超过上界:
- 如果
,就说明 x * y一定超过LIMIT - 这时直接输出
-1 - 否则再执行乘法
正式做法就是:
- 如果
a = 1,直接输出1。 - 从
ans = 1开始,尝试乘b次a。 - 每次乘之前检查
。 - 如果会超界,立刻输出
-1。 - 如果循环正常结束,输出
ans。
代码
cpp
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll LIMIT = 1000000000LL;
ll a, b;
void solve() {
if (a == 1) {
cout << 1 << '\n';
return;
}
ll ans = 1;
// 只要中途超过 1e9,最终答案就已经确定为 -1。
// 当 a >= 2 时,最多乘约 30 次就会超过 1e9,不会真的循环到 1e9 次。
for (ll i = 1; i <= b; i++) {
if (ans > LIMIT / a) {
cout << -1 << '\n';
return;
}
ans *= a;
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> a >> b;
solve();
return 0;
}复杂度
时间复杂度可以看成
空间复杂度是
总结
这题不是快速幂模板题,关键是“有限上界下的截断计算”。
要点只有两个:
- 不需要知道超过
10^9后具体是多少; - 每次乘之前判断是否会超界,超界就立刻停止。