【胡诌】
这道题Claris已经写了题解了,我再写是为了加深理解
【30%】
这个很容易想,暴力嘛
枚举1到n所有的数,对于each i∈[1,n],检验它是否是a[1]...a[m]的约数,如果是,计数器++
这样就统计出了[1,n]内每个数是几个数的约数,然后在统计一下对于[1,m]每个k,cnt[i]=k的有多少个,输出就行了
【40%~60%】
这几个点,只有一个数a[1],当k=1时就是要你统计“有多少个数是1个数的约数”,那既然m=1,所以这“一个数”就是a[1]。就是“有多少个数是a[1]的约数”,也就是“a[1]”有多少约数,当然别忘了是在区间[1,n]中。
那你就直接在sqrt(a)的时间内统计它的约数个数就是了。k=0时的答案就是n-(k=1时的答案)
复杂度O(√a)
【100%】
这个当时没想出来。。。其实现在看来当时挺近了
先不考虑k=0的情况
当k>=1时,只有a[1]...a[m]的约数(当然是各自的约数的并集)才会对答案有所贡献,所以对a[1]...a[m]统计各自的所有因数,然后放到一个map里,看看每个因数出现了多少次,在像上面那样做一下统计就行了。对于k=0的情况,用n减去map的大小就行了。
时间复杂度O( m*sqrt(a)*log2( sqrt(a) ) ) 其中的那个log是使用map算上的
【评测结果】
【代码】
#include <cstdio>
#include <cmath>
#include <map>
using namespace std;
int a[210], n, m, cnt[210];
map<int,int> table;
void push(int x)
{
map<int,int>::iterator it;
it=table.find(x);
if(it==table.end())table[x]=1;
else it->second++;
}
int main()
{
int i, j, t;
map<int,int>::iterator it;
scanf("%d%d",&n,&m);
for(i=1;i<=m;i++)scanf("%d",a+i);
for(i=1;i<=m;i++)
{
t=(int)sqrt(a[i]);
for(j=1;j<=t;j++)
if(a[i]%j==0)
{
if(j<=n)push(j);
if(a[i]/j<=n and j!=a[i]/j)push(a[i]/j);
}
}
for(it=table.begin();it!=table.end();it++)cnt[it->second]++;
printf("%d\n",n-table.size());
for(i=1;i<=m;i++)printf("%d\n",cnt[i]);
return 0;
}