时间限制 $ 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");
}