Divisors

Divisors

给定(m)个不同的正整数(a_1,a_2,...,a_m),请对(0)(m)每一个(k)计算,在区间([1,n])里有多少正整数是(a)中恰好(k)个数的约数。

Input

第一行包含两个正整数(n, m),分别表示区间范围以及(a)数组的大小。
第二行包含(m)个不同的正整数(a_1,a_2, ..., a_m),表示(a)数组。

Output

输出(m+1)行,每行一个整数,其中第(i)行输出(k=i)的答案。

Example

输入 #1

(10) (3)
(4) (6) (7)

输出 #1

(4)
(4)
(1)
(1)

输入 #2

(5) (1)
(8)

输出 #2

(2)
(3)

Scoring

测试点编号 (m) (n,a_i)
(1) (=5) (≤1000)
(2) (=50) (≤1000)
(3) (=200) (≤1000)
(4) (=1) (≤10^9)
(5) (=1) (≤10^9)
(6) (=1) (≤10^9)
(7) (=200) (≤10^9)
(8) (=200) (≤10^9)
(9) (=200) (≤10^9)
(10) (=200) (≤10^9)

题目有点绕,看了好半天
昨天这套题做的太草了

前3个点做法:

暴力枚举(1)(n)每个数,看看它是(a)里几个数的约数

复杂度(O(nm))

第四到第六个点做法:

因为只有一个(a_i),所以枚举(a_i)的约数,这些是(k=1)时的答案,剩下的就是(k=0)

复杂度(O(sqrt{a_i}))

正解:

看一下数据范围,(n)(a_i)都太大了开不起数组,所以大概率对(m)下手

可以把每个(a_i)的约数全部求出来,然后sort,这样所有相同的约数都会挤在一起

然后扫一遍统计个数,放到数组ans里(ans[i] == x表示能被(a)数组中(i)个数整除的数有(x)

以样例1为例:

4的约数:1,2,4,6的约数:1,2,3,6,7的约数:1,7

把这堆数排序之后:1,1,1,2,2,3,4,6,7

有3个1,ans[3]++,2个2,ans[2]++,1个3,ans[1]++,以此类推

最后用(n)减去(sum_{i=1}^n{ans_i})就是ans[0]了

贴代码(不是我的):

#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 ++ ){//找出x的因数放到k数组里
            if( x % j == 0 ){
                k[++cnt] = x / j;
                k[++cnt] = j;
            }
            if( j * j == x)
                cnt --;
        }
    }
    sort( k + 1 , k + cnt + 1 );
    int i = 2 , last = k[1] , tot = 1;
    while( i <= cnt && k[i] <= n ){//扫一遍队列
        if( k[i] != last ){//不一样了
            ans[tot] += 1;//停止计算
            last = k[i];//重新开始
            tot = 1;
        }
        else tot ++;
        i ++;
    }
    ans[tot] += 1;//不要漏掉
    int sum = 0;
    for( int i = 1 ; i <= m ; i ++ )
        sum += ans[i];
    printf( "%d" , n - sum );//算ans[0]
    for( int i = 1 ; i <= m ; i ++ )
        printf( "
%d" , ans[i] );
    return 0;
}

闲话:

昨天爆零了,口区

A题C题MLE,B题传文件的时候系统自动给我重命名了,导致测评姬找不到文件,不知道为啥

A题(就是这题)的MLE还是因为我检查的时候脑子抽了给数组多安了一个0,然后C题是算错

不然预计得分100+40+40

底层群众不敢重测,加上到现在oj上题目都没有放上去,所以也不知道几分不敢乱贴(虽然也没人看),从别人博客转了一个代码过来,批注是自己加工的

参考博客链接:https://blog.csdn.net/weixin_43823476/article/details/87308177

最后是关于计算ans[0]的问题,我自己想出来的做法是在约数放进数组之后,在数组中再添加(1)~(n)的数各一个,最后统计时把ans[tot]++改成ans[tot-1]++,效果应该一样但是绕了个大弯orz

原文地址:https://www.cnblogs.com/Sheffield/p/13489767.html