时间限制 $ 1s$ | 空间限制 \(128M\)

题意:

给你正整数 \(n\)\(m\) 个正整数 \(a_i\)\(1\leq i\leq m\) ),问在区间 \([1,n]\) 有几个数是 \(a_i\)\(1\leq i\leq m\) )中恰好 \(k\) 个数的约数 .

\(1\leq m\leq 200\) \(1\leq n,a_i\leq 10^9\)

30 分:

暴力求解,将每个数分解因数,存到一个桶里记录个数 .

60 分:

考虑处理 \(m=1\) 的情况,记 \(q\)\(a_1\) 的因数个数 , 答案显然为 \(n-q\)\(q\) .

100分:

依旧是暴力分解每个数的因数;

第一种方法:发现最多出现 \(m\sqrt a_i\) 个,可以紧密地统计在 \(d\) 数组中,排序后每个约数在 \(d\) 数组中必然相邻,直接统计即可 .

第二种方法:用 \(t_i\) 表示因数 \(i\) 出现的次数 ,\(p_i\) 表示作为 \(a_1\)\(a_j\) 中恰好作为 \(i\) 个数因数的数的个数(也就是答案),在输入每个 \(a_i\) 的同时统计 \(t_i\)\(p_i\) ,当又找到了一个因数时,需要更新:

void update(int x)
{
    p[t[x]]--,t[x]++,p[t[x]]++;
}

答案即为 \(p_0\)\(p_m\) .

代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int p[201],a[205];
map<int,int>t;
void update(int x)
{
    p[t[x]]--,t[x]++,p[t[x]]++;
}
int main()
{
    freopen("divisors.in","r",stdin);
    freopen("divisors.out","w",stdout);
    cin>>n>>m;
    p[0]=n;
    for(int i=1;i<=m;i++)
    {
        cin>>a[i];
        for(int j=1;j*j<=a[i];j++)
        {
            if(a[i]%j==0)
            {
                update(j);
                if(j!=a[i]/j&&a[i]/j<=n)
                {
                    update(a[i]/j);
                }
            }
        }
    }
    for(int i=0;i<=m;i++)
    {
        cout<<p[i]<<"\n";
    }
    system("pause > nul");
}