4854 -- 【NOIP2016模拟1】Divisors
Description
给定m个不同的正整数 a1,a2,...,am,对[0,m]内每一个k计算:在区间[1,n]里有多少正整数是a中恰好k个数的约数。
Input
第一行输入n,m。
第二行m个正整数表示ai.
Output
输出0~m行,第i行表示[1,n]里有多少正整数是a中恰好i个数的约数。
Sample Input
100
3 3 8 15
Sample Output
93
5
1
1
Hint
30% :n<=10,m<=5,ai<=100
60% :n<=1000,m<=100,ai<=10^6
100% :n<=10^9,m<=200,ai<=10^9
题解:
60%直接hash过。
100%的数据我们可以考虑m的范围很小,可以采取一点特殊措施,把a[i]的所有因数放进数组里然后sort,这样就可以简单求解了。
还有一种方法是用链式hash
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
int pri[100005],cnt=0,n,m,a[205],ans[205],tot=0;
void pre(int x)
{
for(int i=1;i*i<=x;i++)
{
if(x%i==0)
{
pri[++cnt]=i;
if(x!=i*i)pri[++cnt]=x/i;
}
}
}
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
{
cin>>a[i];
pre(a[i]);
}
pri[++cnt]=0x7fffffff;
sort(pri+1,pri+cnt+1);
int t=1;
for(int i=1;i<cnt;i++)
{
if(pri[i]>=n)break;
if(pri[i]==pri[i+1])t++;
else
{
ans[t]++;
t=1;
tot++;
}
}
cout<<n-tot<<endl;;
for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
return 0;
}
//链hash法
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
using namespace std;
const int md=1001003,MX=10000005;
int a[210],ans[210];
int h[MX],next[MX],cnt[MX];
int head[md];
int sz,n,m,i,tot;
void insert(int x){//插入hash表
int i,j;
j=x%md;
if (head[j]==0) {
sz++;head[j]=sz;
h[sz]=x;cnt[sz]=1;
return;
}
i=head[j];
while (next[i]!=0)
{
if (h[i]==x) { cnt[i]++;return ;}
i=next[i];
}
if(h[i]==x){cnt[i]++;return;}
sz++;next[i]=sz;
h[sz]=x;cnt[sz]=1;
}
void calc(int x)//求x的约数
{
for(int i=1;i*i<=x;i++)
if (x%i==0) {
insert(i);
if (i!=x/i) insert(x/i);}
}
int main()
{
cin>>n>>m;
sz=0;
for(int i=1;i<=m;i++)cin>>a[i],calc(a[i]);
tot=0;
for (int i=1;i<=sz;i++)
if (h[i]<=n){//n范围内
tot++;
if (cnt[i]<=m) ans[cnt[i]]++;//统计
}
cout<<n-tot<<endl;
for(int i=1;i<=m;i++)cout<<ans[i]<<endl;
return 0;
}