链接:http://oj.hzjingma.com/p/7809?view=classic
来源:竞码编程
题目描述
求所有 到 的整数中,因数个数第 少的数因数个数是多少。
输入描述
第一行两个正整数 , 即题目描述中的 , 。
输出描述
输出仅一行,即因数个数第 少的数因数个数。
输入
10 5
输出
3
解法一:直接暴力求解, 判断因子个数。复杂度 ,对于此题目来说会 。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e7 + 10;
ll cnt[maxn];
set<ll>s;
ll cal(int x) {
ll cnt1 = 2;
if(x == 1)
return 1;
for(ll i = 2; i * i <= x; i++) {
if(x % i == 0) {
if(i * i == x)
cnt1++;
else
cnt1 += 2;
}
}
return cnt1;
}
int main() {
int n, k;
scanf("%d%d", &n, &k);
for(int i = 2; i <= n; i++)
cnt[i] = cal(i);
sort(cnt + 1, cnt + n + 1);
//for(int i=2;i<=n;i++) cout<<cnt[i]<<" "<<endl;
printf("%lld\n", cnt[k + 1]);
/*s.insert(cal(i));
int cnt2=0;
for(set<ll>::iterator it=s.begin();it!=s.end();it++) cnt[cnt2++]=*it;
sort(cnt,cnt+cnt2);*/
return 0;
}
解法二:用类似于埃式筛法的方法从 此把每个数的倍数因子 , 之后直接输出结果。复杂度: ,这个 能跑过去 的代码。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e7 + 10;
int cnt[maxn];
inline int read() {
int x = 0, neg = 1;
char op = getchar();
while (!isdigit(op)) {
if (op == '-')
neg = -1;
op = getchar();
}
while (isdigit(op)) {
x = 10 * x + op - '0';
op = getchar();
}
return neg * x;
}
inline void print(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x >= 10)
print(x / 10);
putchar(x % 10 + '0');
}
int main() {
int n, k;
n = read();
k = read();
if(n >= maxn)
puts("2");
else {
for(int i = 2; i <= n; i++) {
cnt[i] += 2;
for(int j = 2 * i; j <= n; j += i)
cnt[j]++;
}
sort(cnt + 1, cnt + n + 1);
print(cnt[k + 1]);
}
return 0;
}
解法三:我们可以知道,对于每一个数
都可以分解成如下的式子
表示质因子,
表示质因子的个数
那个就有
的因子个数
在欧拉筛的过程中,当
为素数的时候,
(素数只有两个因子),此时我们在使用一个数组
来表示
的最小质因子的个数,此时
,这个素数当前的质因子只有
个。
当
的时候:
那么
就是
中的最小质因子的个数加一
此时就有
,
的 最小质因子数加一就是
的最小质因子的个数,此时这个数的因子个数就会随之改变,就变成了
,
是原本
的最小质因子的个数,
则是现在这个数的最小质因子的个数,所以就可以得到
加一表示
也是这个数的因子,然后退出这层循环,因为后面的数会在遍历其他数字的时候被筛去。
当
的时候:
说明
中没有这个这个素数,那么
就多了一种素数,这个素数出现的次数
,因子个数
。
复杂度:
#include<bits/stdc++.h>
using namespace std;
const int maxn = 2e7 + 10;
int cnt[maxn] = {0, 1}, times[maxn], prime[maxn], num1[maxn]; //最小质因子出现次数
bool is_prime[maxn];
inline int read() {
int x = 0, neg = 1;
char op = getchar();
while (!isdigit(op)) {
if (op == '-')
neg = -1;
op = getchar();
}
while (isdigit(op)) {
x = 10 * x + op - '0';
op = getchar();
}
return neg * x;
}
inline void print(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x >= 10)
print(x / 10);
putchar(x % 10 + '0');
}
void solve() {
for(int i = 2; i <= maxn; i++)
is_prime[i] = true;
is_prime[0] = is_prime[1] = false;
int num = 0;
for(int i = 2; i <= maxn; i++) {
if(is_prime[i]) {
cnt[i] = 2;
times[i] = 1;
prime[num++] = i;
}
for(int j = 0; j < num; j++) {
if(i * prime[j] > maxn)
break;
is_prime[i * prime[j]] = false;
if(i % prime[j] == 0) { //当前素数是最小质因子
times[i * prime[j]] = times[i] + 1;
cnt[i * prime[j]] = cnt[i] / (times[i] + 1) * (times[i * prime[j]] + 1);
break;
}
times[i * prime[j]] = 1;
cnt[i * prime[j]] = cnt[i] * 2;
}
}
}
int main() {
solve();
int n, k;
n = read();
k = read();
if(n >= maxn)
puts("2");
else {
//for(int i=2;i<=n;i++) cout<<cnt[i]<<" "; cout<<endl;
for(int i = 2; i <= n; i++)
num1[cnt[i]]++;
//for(int i=2;i<=n;i++) cout<<num1[i]<<" "; cout<<endl;
int cnt1 = 0;
for(int i = 2; i <= n; i++) {
while(num1[i]--)
++cnt1;
if(cnt1 >= k) {
print(i);
break;
}
}
}
return 0;
}