title: 组合数学与计数原理
tags: []
categories: [OI, 算法专题]
| N中的元素 | X中的元素 | f任意 | f单射 | f满射 |
|---|---|---|---|---|
| 可区分 | 可区分 | \(x^n\) | ||
| 不可区分 | 可区分 | \(\binom{n}{x+n-1}\) | ||
| 可区分 | 不可区分 | |||
| 不可区分 | 不可区分 |
P9118 春季测试 2023 幂次
题意
- 求 \(1 \sim n\) 中有多少正整数可以表示为 \(a^b\) 的形式,其中 \(a, b\) 为正整数且 \(b \ge k\)。同一个数的多种表示只计一次。
数据范围:\(1 \le n \le 10^{18}\),\(1 \le k \le 100\)。
思路
有点人类智慧的一个题。
k=1时显然答案是n。
k>2时答案很好统计,因为1e18的sqrt3只有1e6个,枚举然后再while指数就可以了。
当指数是2时,显然是sqrt2。但是有的答案在指数>2时也被统计了,就需要减去重复的部分。做法是在循环中如果是完全平方的数就统计,最后减去就好了。
代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define F(i,a,b) for(int i=(a);i<=(b);i++)
#define Dl(a) cout << #a << " : " << a << "\n";
#define D(a) cout << #a << " : " << a;
#define Da(a,i,j) cout << #a << " : ";f(idx,i,j){cout << a[idx] <<" ";}
int n,k;
map <int,bool> mp;
int pow3,pow2AndPow3;
void solve(){
for (int i=2;i*i*i<=n;i++){
// Dl(i);
int d = i * i,p = 2;
while (d<= n / i){
p ++;
d *= i;
if (mp[d]) continue;
if (p < k) continue;
mp[d] = 1,pow3 ++;
if ((int)sqrtl(d) * (int)sqrtl(d) == d){
// Dl(sqrtl(d));
// Dl(d);
pow2AndPow3++;
}
// D(d);Dl(p);
}
}
}
signed main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
cin >> n >> k;
if (k == 1) cout << n;
else if (k >= 3){
solve();
cout << pow3 + 1;
}
else{
solve();
// Dl(pow3);
// Dl(pow2AndPow3);
cout << (long long)sqrtl(n) + pow3 - pow2AndPow3;
}
return 0;
}
浙公网安备 33010602011771号