合数是指在大于1的整数中除了能被1和本身整除外,还能被其他数(0除外)整除的数。
现在,请你求在一个合数的因子中,有几个因子是合数。例如,16的因子有1,2,4,8,16,其中4,8,16为合数,它有3个因子为合数。
现在,请你求范围1至n中,因子中合数个数为x的数的数量(多次询问)。
输入格式:
第一行输入两个整数 n,m(1≤n,m≤10
5
) 表示范围以及询问次数。
接下来 m 行,每行一个正整数 x(1≤x≤n),查询范围1至n中,因子中合数个数为x的数的数量
输出格式:
一个整数,即满足题意的答案。
输入样例:
在这里给出一组输入。例如:
10 5
1
2
3
4
5
思路
因为要计算1~n有多少个因子是合数,这里用i表示正在判断的数,因此我们必须要在找到一个数的因子之后,再进行判断是不是合数。显然除了1*i,所有的因子都是小于i的(在计算到i之前我们已经计算过这些数是否为合数),为了避免对这些数进行重复判断,因此用一个数组adjust来记录数字是否为合数,是的话记为1,不是则记为0。
判断一个数i是不是合数就是,除了1和本身外,还能被其他数整除,就每次从2开始尝试除这个数,在这里一旦可以除尽我们就将adjust[i]标记为1,我们用一个数组sum来存储一个数的合数因子的个数,为了省事,我们只进行到sqrt(i),因为已知J可以被i整除的话,i/j一定以可以被i整除,再通过adjust数组判断j和i/j是否为合数,是的话就sum[i]+1。当然sqrt[i]是一个例外,只用判断j就可以了。要注意一个特殊的点的是,如果这个数本身是一个合数的话,那么他本身也是一个合数因子。
现在我们已知1~n所有数字的因子中合数的个数,为了查询数量方便,避免多次重复遍历sum数组,再建立一个数组result,用result[i]来存储因子中合数个数为i的数量。最后根据输入的数据直接调取result[i]中的信息就可。
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;
int main()
{
int n, m;
cin >> n >> m;
vector<int> adjust(n + 1, 0);
vector<int> sum(n + 1, 0);
//显然1,2,3不是合数
for (int i = 4; i < n+1; i++)
{
for (int j = 2; j <= sqrt(i); j++)
{
if (i % j == 0)
{
adjust[i] = 1;
//当J不是sqrt(i)时,要判断j和i/j.
if (j != sqrt(i))
{
if ( adjust[j] == 1)
{
sum[i]++;
}
if (adjust[i / j] == 1)
{
sum[i]++;
}
}//是sqrt(i)时只用判断j,因为此时i/j=j;
else
{
if (adjust[j] == 1)
{
sum[i]++;
}
}
}
}
if (adjust[i]==1)
{
sum[i]++;
}
}
//计算因子中合数为i的数量
vector<int> result(n + 1,0);
for (int i = 0; i <= n; i++)
{
result[sum[i]]++;
}
/*for (int i = 0; i <=n; i++)
{
cout<<i<<':'<< adjust[i]<<"间隔"<<sum[i]<<"间隔"<<result[i]<<endl;
}*/
//打印结果
int i;
while (m--)
{
cin >> i;
cout << result[i]<<endl;
}
}