题目描述
给定m 个不同的正整数a1,a2,.... am,请对0 到m 每一个k 计算,在区间[1, n] 里有多少正整数
是a 中恰好k 个数的约数。
输入
第一行包含两个正整数n,m,分别表示区间范围以及a 数组的大小。
第二行包含m 个不同的正整数a1,a2,.... am,表示a 数组。
输出
输出m + 1 行,每行一个整数,其中第i 行输出k = i 的答案。
样例输入
10 3
4 6 7
样例输出
4
4
1
1
数据范围
m<=200,n<=10^9,ai<=10^9
题目有点绕,分析一下:
4 : 1 2 4
6: 1 2 3 6
7: 1 7
在1到10中,只有1是a中3个数的约数,2是a中2个数的约数,3,4,6,7分别是a中一个数的约数
具体分析
首先容易判断是数论中求公约数的问题。
我们可以先将每个数的约数求出来,然后难点在于统计
由于是128MB,且n<=10^9,ai<=10^9,若开bool不现实。
所以我们可以定义:
ans[i]表示在区间内,恰好是a中i个数的约数 的个数
然后我们统计就行了
用sort,具体实现可以看代码
代码实现:
#include <cstdio>
#include <iostream>
#include <vector>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int MAXN = 1e7 + 3;
int cnt , k[MAXN] , m , x , n;
int ans[203];
int main(){
scanf( "%d%d" , &n , &m );
for( int i = 1 ; i <= m ; i ++ ){
scanf( "%d" , &x );//输入
for( int j = 1 ; j * j <= x ; j ++ ){
if( x % j == 0 ){
k[++cnt] = x / j;
k[++cnt] = j;
}//快捷找它的所有因数
if( j * j == x )
cnt --;//判断x是否为完全平方数
}
}
sort( k + 1 , k + cnt + 1 );
int i = 2 , last = k[1] , tot = 1;
while( i <= cnt && k[i] <= n ){
if( k[i] != last ){//由于每个因子在x中只存放了一次,且我们用了排序
ans[tot] += 1;//所以如果连续tot个都是同一个数,则说明a中有i个数的公因数有这个数
last = k[i];//如果不是,就替换
tot = 1;
}
else
tot ++;
i ++;
}
ans[tot] += 1;//这里while只会最多循环cnt-1次,所以tot里的值不能忽略
int sum = 0;
for( int i = 1 ; i <= m ; i ++ )
sum += ans[i];
printf( "%d" , n - sum );//1到n中每个数只会在ans中加一次,算出sum(ans),就能推出ans[0]
for( int i = 1 ; i <= m ; i ++ )
printf( "\n%d" , ans[i] );
return 0;
}