P1221 最多因子数 题解

· · 题解

不保证能通过数据范围下所有数据。 [将素数筛到 $50000$ 时的记录](https://www.luogu.com.cn/record/79789362)。 [题目传送门。](https://www.luogu.com.cn/problem/P1221) ## 题目分析 如果直接暴力枚举上界与下界的因数个数并比较,复杂度过高,不可接受。 考虑直接打表输出 $1$ 到 $10^9$ 的因数轻轻松松 `MLE` 且超过 $50\text{KB}$。 考虑分段打表。 以 $10^6$ 为一段,从 $1$ 一直枚举到 $10^9$,输出的表的第 $i$ 项表示 $10^6\times (i-1)+1$ 到 $10^6\times i$ 中因数最多的数及它的因数个数。 但是你会发现程序运行得很慢……所以可以先写一个程序计算 $1$ 到 $3\times 10^4$ 中的所有质数,打表存在打表程序里,枚举时直接从 `pr[]` 数组中的质数判断,减少了运行时间,之后就从 $3\times 10^4+11$ 开始枚举。(而这时该数可能已经变小很多) ```cpp #include<bits/stdc++.h> using namespace std; const int pr[]={}; inline int fun(int a){ int ans=1; for(int i=1;i<sizeof(pr)/sizeof(int)&&pr[i]*pr[i]<=a;++i){ int cnt=1; while(a%pr[i]==0)cnt++,a/=pr[i]; ans=ans*cnt; } for(int i=30011;i*i<=a;++i){ int cnt=1; while(a%i==0)cnt++,a/=i; ans=ans*cnt; } if(a!=1)ans<<=1; return ans; } signed main(){ printf("{{0,0},") ; int l=1,r=1e9,maxn=-1,ans; for(int i=l;i<=r;++i){ if(fun(i)>maxn)maxn=fun(i),ans=i; if(i%1000000==0){ printf("{%d,%d}",ans,maxn); if(i!=r)printf(","); else printf("}"); maxn=-1; } } return 0; } ``` 最后计算,如果 $\lfloor \dfrac{l}{10^6}\rfloor=\lfloor\dfrac{u}{10^6}\rfloor$,就进行暴力。 否则在将 $l$ 到 $\lceil\dfrac{l-1}{10^6}\rceil\times 10^6$ 和 $\lfloor\dfrac{u}{10^6}\rfloor\times 10^6+1$ 到 $u$ 暴力求解,枚举表中 $\lceil\dfrac{l-1}{10^6}\rceil$ 到 $\lfloor\dfrac{u}{10^6}\rfloor$ 即可。 代码: ```cpp #include<bits/stdc++.h> using namespace std; const int pr[]={}; int fun(int a) { int ans=1; for(int i=1;i<sizeof(pr)/sizeof(int)&&pr[i]*pr[i]<=a;++i){ int cnt=1; while(a%pr[i]==0)cnt++,a/=pr[i]; ans=ans*cnt; } for(int i=30011;i*i<=a;++i){ int cnt=1; while(a%i==0)cnt++,a/=i; ans=ans*cnt; } if(a!=1)ans<<=1; return ans; } int a[][2]={}; signed main(){ int l,u,j,maxn=-1,ans; scanf("%d %d",&l,&u); if(l/1000000==u/1000000){ for(register int i=l;i<=u;++i){ int x=fun(i); if(x>maxn)maxn=x,ans=i; } } else { for(j=l;;++j){ if(j%1000000==1)break; int x=fun(j); if(x>maxn)maxn=x,ans=j; } for(register int i=j/1000000+1;i<=u/1000000;++i){ if(a[i][1]>maxn)maxn=a[i][1],ans=a[i][0]; } for(register int i=u/1000000*1000000+1;i<=u;++i){ int x=fun(i); if(x>maxn)maxn=x,ans=i; } } printf("Between %d and %d, %d has a maximum of %d divisors.",l,u,ans,maxn); return 0; } ``` 由于代码较长,`pr[]` 数组和 `a[][]` 数组在这里无法给出,请去[这里](https://www.luogu.com.cn/problem/U228570)下载。 评测记录:[不吸氧](https://www.luogu.com.cn/record/79787094),[吸氧](https://www.luogu.com.cn/record/79787759)。