题目描述
小 Ω 在小学数学课上学到了“幂次”的概念:\forall a, b \in \N^+∀a,b∈N+,定义 a^bab 为 bb 个 aa 相乘。
她很好奇有多少正整数可以被表示为上述 a^bab 的形式?由于所有正整数 m \in N^+m∈N+ 总是可以被表示为 m^1m1 的形式,因此她要求上述的表示中,必须有 b \geq kb≥k,其中 kk 是她事先选取好的一个正整数。
因此她想知道在 11 到 nn 中,有多少正整数 xx 可以被表示为 x = a^bx=ab 的形式,其中 a, ba,b 都是正整数,且 b \geq kb≥k?
输入格式
第一行包含两个正整数 n, kn,k,意义如上所述。
输出格式
输出一行包含一个非负整数表示对应的答案。
输入输出样例
输入 #1复制
99 1
输出 #1复制
99
输入 #2复制
99 3
输出 #2复制
7
输入 #3复制
99 2
输出 #3复制
12
说明/提示
【样例 2 解释】
以下是全部 77 组符合题意的正整数及对应的一种合法的表示方法。
1 = 1^3, 8 = 2^3, 16 = 2^4, 27 = 3^3, 32 = 2^5, 64 = 4^3, 81 = 3^41=13,8=23,16=24,27=33,32=25,64=43,81=34
注意某些正整数可能有多种合法的表示方法,例如 6464 还可以表示为 64 = 2^664=26。
但根据题意,同一个数的不同的合法表示方法只会被计入一次。
【样例 3 解释】
以下是全部 1212 组符合题意的正整数及对应的一种合法的表示方法。
1 = 1^2, 4 = 2^2, 8 = 2^3, 9 = 3^2, 16 = 4^2, 25 = 5^2, 27 = 3^3, 32 = 2^5, 36 = 6^2, 49 = 7^2, 64 = 8^2, 81 = 9^21=12,4=22,8=23,9=32,16=42,25=52,27=33,32=25,36=62,49=72,64=82,81=92
【样例 4】
见选手目录下的 power/power4.in 与 power/power4.ans。
【样例 5】
见选手目录下的 power/power5.in 与 power/power5.ans。
【样例 6】
见选手目录下的 power/power6.in 与 power/power6.ans。
【数据范围】
对于所有数据,保证 1 \leq n \leq 10^{18}1≤n≤1018,1 \leq k \leq 1001≤k≤100。
测试点编号 | n \len≤ | kk |
---|---|---|
1 | 10^2102 | =1=1 |
2 | 10^2102 | \ge 2≥2 |
3 | 10^4104 | \ge 3≥3 |
4 | 10^4104 | \ge 2≥2 |
5 | 10^6106 | \ge 3≥3 |
6 | 10^6106 | \ge 2≥2 |
7 | 10^8108 | \ge 3≥3 |
8 | 10^8108 | \ge 2≥2 |
9 | 10^{10}1010 | \ge 3≥3 |
10 | 10^{10}1010 | \ge 2≥2 |
11 | 10^{12}1012 | \ge 3≥3 |
12 | 10^{12}1012 | \ge 2≥2 |
13 | 10^{14}1014 | \ge 3≥3 |
14 | 10^{14}1014 | \ge 2≥2 |
15 | 10^{16}1016 | \ge 3≥3 |
16 | 10^{16}1016 | \ge 2≥2 |
17 | 10^{18}1018 | \ge 3≥3 |
18 | 10^{18}1018 | \ge 2≥2 |
19 | 10^{18}1018 | \ge 2≥2 |
20 | 10^{18}1018 | \ge 2≥2 |
附件下载
power6.ans11B
power6.in22B
power5.in22B
power4.in16B
Solution
考虑一个比较简单的暴力,枚举 [1,n][1,n] 中的每个数作为 aa,然后枚举 bb,直到 a^b \ge nab≥n 就让 a++
然后重新枚举 bb,每个没出现过的数使 ans++
。
先不考虑去重,我们来思考如何优化这个暴力。注意到当我们枚举的 bb 增加时,使 a^bab 首次 \ge n≥n 的 aa 会越来越小,由此我们可以对每个 bb 二分求出一个 aa 的上界,此时 aa 的上界是 nn 次根号级别的。
因为 2^{60} \ge 10^{18}260≥1018 ,所以 bb 实际的范围并不大。对于 k \ge 3k≥3 的情况我们都可以枚举 bb 求出 aa 的上界然后直接暴力求所有快速幂做了。剩下的情况中,k = 1k=1 时答案显然为 nn,那么 k = 2k=2 时如何做?
此时回来考虑去重,因为笔者太菜了赛时没想到容斥怎么做,所以求完快速幂后再枚举每个 \le b≤b 的 xx 作为新的指数。然后对当前求得的 a^bab 开 xx 次方根,看是否有正整数解,就可以判定是否与之前计算过的重复了。
此时 k = 2k=2 的情况就迎刃而解了,我们直接令初始 ans
为 \sqrt{n}n 即可。
还要注意 aa 为 11 的情况,在初始答案上略作修改就行。
时间复杂度比较抽象,我不会表示,算了算可过。
Code
#include <bits/stdc++.h>
#define e118 1000000000000000000ll
//#define __int128 long long
using namespace std;
inline long long read()
{
long long r = 0, c = getchar(), f = 1;
while (c < '0' || c > '9')
{
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') r = (r << 1) + (r << 3) + (c ^ 48), c = getchar();
return r * f;
}
long long qpow(__int128 a, int b)
{
__int128 res = 1;
while (b)
{
if (a > e118) return e118 + 1;
if (b & 1) res = res * a;
a = a * a;
b >>= 1;
}
return res > e118 ? e118 + 1 : res;
}
long long get_sqrt(long long n, int x)
{
long long l = 1, r = n, ans;
while (l <= r)
{
long long mid = l + r >> 1;
if (qpow(mid, x) <= n) l = mid + 1, ans = mid;
else r = mid - 1;
}
return ans;
}
int main()
{
// freopen("power.in", "r", stdin);
// freopen("power.out", "w", stdout);
long long n = read(), ans = 1;
int k = read();
if (k == 1) printf("%lld\n", n), exit(0);
if (k == 2) ans += (long long)get_sqrt(n, 2) - 1;
for (int i = max(k, 3); i <= 60; ++i)
{
int lim = get_sqrt(n, i);
for (int j = 2; j <= lim; ++j)
{
long long now = qpow(j, i);
bool flag = 1;
for (int l = max(k, 2); l < i; ++l)
{
long long rt = get_sqrt(now, l);
if (qpow(rt, l) == now) flag = 0;
}
ans += flag;
}
}
printf("%lld\n", ans);
return 0;
}