刚开始把题意理解错了
先埃筛筛出合数,再算出1~n的合因子数 其实直接开个数组记录相同合因子数的个数就行了(ans[num[i]]++)
也就是桶排序
没必要先sort排序,再统计各合因子数的个数 而当时为了O(n)统计 不得不按合因子个数从小到大依次计算 也就是先找到该合因子个数的起点 再找到终点
其实也可以两次二分找该合因子个数的起点和终点
找起点时判定条件为mid<k 此时l为起点
找终点时判定条件为mid≤k 此时r为终点
两次二分结束l=r+1
注意:埃筛复杂度nlog(log n)
#include<bits/stdc++.h>//两次二分找 #define ll long long using namespace std; const int N=1e5+5; int vis[N],num[N],ans[N]; int main(){ int n,m; cin>>n>>m; for(int i=2;i<=n;i++){ if(vis[i])continue; for(int j=i;j<=n/i;j++)vis[i*j]=1; } for(int i=2;i<=n;i++) for(int j=1;j<=sqrt(i);j++){ if(vis[j]&&i%j==0)num[i]++; int x=i/j; if(x*j==i&&vis[x]&&i%x==0&&j!=x)num[i]++; } sort(num+1,num+1+n); //for(int i=1;i<=n;i++)cout<<num[i]<<endl; int s=0; // for(int i=1;i<=n;i++) // if(!pos[num[i]])pos[num[i]]=i; for(int i=1;i<=num[n];i++){ while(num[s]<i&&s<=n)s++; //cout<<i<<' '<<s<<endl; ans[i]-=s; while(num[s]==i&&s<=n)s++; //cout<<i<<' '<<s<<endl; ans[i]+=s; //while(num[s]<i&&s)s--; } for(int i=1;i<=m;i++){ int k; cin>>k; if(k>num[n])cout<<0<<endl; else cout<<ans[k]<<endl; } return 0; }
std
#include<bits/stdc++.h> using namespace std; const int MAXN=100005; int f[MAXN],cnt[MAXN],n,m,x; bool prim[MAXN]; void init(int n) { for(int i=2;i<=n;++i) { prim[i]=true; } for(int i=2;i<=n;++i) { if(prim[i]) { for(int j=i+i;j<=n;j+=i) { prim[j]=false; } } else { for(int j=i;j<=n;j+=i) { cnt[j]++; } } f[cnt[i]]++; } } int main() { scanf("%d %d",&n,&m); init(n); while(m--) { scanf("%d",&x); printf("%d\n",f[x]); } }