链接:https://ac.nowcoder.com/acm/contest/3004/H
题目描述
合数是指自然数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
牛牛最近在研究“k合因子数”,所谓“k合数”是指一个数的所有因子中,是合数的因子共有k个。
例如20的因子有1,2,4,5,10,20,其中4,10,20为合数,它有3个合数因子,就称20是一个 “3合因子数”
牛牛想要知道1~n中给定k的情况下k合因子数的数目。
输入描述:
第一行输入两个数字n,m(1≤n,m≤10^5)
表示范围以及查询“k”的数目
接下来m行,每行一个正整数k(1≤k≤n)
查询k合因子数的数目。
输出描述:
一行一个数字,表示k合因子数的数目
输入
10 5
1
2
3
4
5
输出
4
1
0
0
0
说明
1~10的范围内
1合因子数有:4,6,9,10,共4个
2合因子数有:8,共1一个
像中学学新课一样,学了一个新知识点后忍不住反复用,所以,,,
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <math.h>
#include <map>
#include <queue>
#define mo 1000000007
using namespace std;
typedef long long ll;
int ans[100006], anss[100006];
int fun(int n)
{
int i, a, ans = 1, pri_fac = 0;
for(i = 2; i*i <= n; i++)
{
if(n%i == 0)
{
a = 0;
while(n%i == 0)
{
n /= i;
a++;
}
pri_fac++; //唯一分解定理,求出 n 的素因子 i 总数
ans = ans * (a+1); // 唯一分解定理相关公式应用,求出总因子数
}
}
if(n > 1)
{
pri_fac++;
ans *= 2;
}
return ans - pri_fac - 1; // 合因子数 = 总 - 素 - 1,(1既不是素数也不是合数(*^▽^*))
}
int main()
{
int n, m, i, k;
scanf("%d%d", &n, &m);
for(i = 1; i <= n; i++)
anss[fun(i)]++;
while(m--)
{
scanf("%d", &k);
printf("%d\n", anss[k]);
}
return 0;
}
虽然比较长,但是很直观很好想,AC之后觉得自己无比机智,直到知道这是埃氏筛,,,另一种做法:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <math.h>
#include <map>
#include <queue>
#define mo 1000000007
using namespace std;
typedef long long ll;
const int Maxn = 100006;
int ans[Maxn], cnt[Maxn];
bool prime[Maxn];
int main()
{
int n, m, k, i, j;
scanf("%d%d", &n, &m);
for(i = 2; i <= n; i++)
prime[i] = 1; //假设最初都是素数,用埃氏筛
for(i = 2; i <= n; i++)
{
if(prime[i])
for(j = i+i; j <= n; j += i)
prime[j] = 0; // i 是素数,其倍数 j 都是合数
else
for(j = i; j <= n; j += i)
cnt[j]++; // i 是合数,其倍数 j 都是是含有合数因子 i 的数,j 的合因子数+1 (更新一遍)
}
for(i = 2; i <= n; i++)
ans[cnt[i]]++; //cnt[i]是 i 的合因子数,已经更新完毕, ans[cnt[i]] 是合因子数为cnt[i]的数的数目
while(m--)
{
scanf("%d", &k);
printf("%d\n", ans[k]);
}
return 0;
}