[春季测试 2023] 幂次

题目描述

小 Ω 在小学数学课上学到了“幂次”的概念:\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
110^2102=1=1
210^2102\ge 2≥2
310^4104\ge 3≥3
410^4104\ge 2≥2
510^6106\ge 3≥3
610^6106\ge 2≥2
710^8108\ge 3≥3
810^8108\ge 2≥2
910^{10}1010\ge 3≥3
1010^{10}1010\ge 2≥2
1110^{12}1012\ge 3≥3
1210^{12}1012\ge 2≥2
1310^{14}1014\ge 3≥3
1410^{14}1014\ge 2≥2
1510^{16}1016\ge 3≥3
1610^{16}1016\ge 2≥2
1710^{18}1018\ge 3≥3
1810^{18}1018\ge 2≥2
1910^{18}1018\ge 2≥2
2010^{18}1018\ge 2≥2

附件下载

power6.ans11B

power6.in22B

power5.ans8B

power5.in22B

power4.ans8B

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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值