[题解] P9118 [春季测试 2023] 幂次
这个题一看就很普及。我们分情况考虑:
k=1
显然直接输出
k\ge 3
发现
错了。注意到不同底数的不同次幂可能相同,所以需要判重。这里我使用了 map 判重。令
看起来很暴力,但可以通过,并且并不需要用容斥什么的动脑子。
k=2
为什么要单独讲
思考我们枚举的本质是什么?统计答案?不是,如果只是统计答案的话,那么二分或者其他方法肯定更快。那为什么要一个个枚举?是因为要判重。那么,如果我们对完全平方数能找到一个更好的性质用于判重,就可以避免对于指数为
这个时候就要思考完全平方数的性质了,最常用的一点就是,分解质因数后所有指数都是偶数。那么,我们先把
好想好写,适合做一道普及组的题。
Code:
#include <bits/stdc++.h>
using namespace std;
#define int long long
int n, k, ans=1, pf[1000010];
map <int, int> mp;
int sqrt(int x){
int l = 0, r = 1e9;
while (l <= r){
int mid = l + r >> 1;
if (mid * mid <= x) l = mid + 1;
else r = mid - 1;
}
return l - 1;
}
signed main(){
scanf ("%lld%lld", &n, &k);
if (k == 1) return printf ("%lld\n", n), 0;
if (k == 2){
ans = sqrt(n);
for (int i=1; i<=1000; i++) pf[i*i] = 1;
if (k == 2) k = 3;
for (int i=2; i; i++){
if (mp.find(i) != mp.end() || pf[i]) continue;
int now = 1, flag = 0;
for (int j=1; j<=k; j++){
if (now > n / i){
flag = 1;
break;
}
now *= i;
}
if (flag) break;
for (int j=k; j; j++){
if (mp.find(now) == mp.end() && j % 2 == 1) ans ++;
mp[now] = 1;
if (now > n / i) break;
now *= i;
}
}
}
if (k >= 3){
for (int i=2; i; i++){
if (mp.find(i) != mp.end()) continue;
int now = 1, flag = 0;
for (int j=1; j<=k; j++){
if (now > n / i){
flag = 1;
break;
}
now *= i;
}
if (flag) break;
for (;;){
if (mp.find(now) == mp.end()) ans ++;
mp[now] = 1;
if (now > n / i) break;
now *= i;
}
}
}
printf ("%lld\n", ans);
return 0;
}