AT_jag2017autumn_c Prime-Factor Prime
题目描述:
把一个数\(N\)分解质因数,比如\(210=2\times3\times5\times7,8=2\times2\times2\)。设\(f(x)\)即为\(x\)按如上方法分解后得到的数字个数。有多少个数满足\(f(x)\ (x\in [l,r],x \in Z)\)为质数?比如\(8\)就满足要求。
数据范围:
\(1\le l,r\le 10^9\)
\(0\le r-l\le 10^6\)
思路:
我们发现这个范围非常大,所以我们考虑一种筛质数常见的优化方式:只处理 \(\le \sqrt n\) 的所有质数,如果一个数分解完之后还有剩余,则剩下的那个一定是一个质数
对于这个东西的证明 \(\downarrow\)
证明过程
我们等于是需要证明任意一个大于 \(\sqrt n\) 的数的质因数只有一个大于 \(\sqrt n\)
考虑反证法:
如果存在两个大于 \(\sqrt n\) 的数,则两个数的乘积肯定大于 \(n\)
所以只会有一个大于 \(\sqrt n\) 的质数存在。
显然我们对于每个质数不能全部枚举整个区间,这样显然会寄。所以我们不妨只枚举质数的倍数。
所以应该从 \(\lfloor \frac{l+prim-1}{prim}\rfloor \times prim\) 开始枚举倍数。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e6+5;
const int lim=31623;
int l,r;
int prim[maxn],vis[maxn];
int cnt;
void init(){
vis[0]=vis[1]=1;
for(int i=2;i<=lim;i++){
if(!vis[i]){
prim[++cnt]=i;
for(int j=i+i;j<=lim;j+=i)vis[j]=1;
}
}
}
int num[maxn];
int p[maxn];
signed main(){
cin>>l>>r;
init();
if(r<lim){
for(int i=1;i<=cnt;i++){
for(int j=l;j<=r;j++){
int t=j;
while(t%prim[i]==0)num[j]++,t/=prim[i];
}
}
int ans=0;
for(int i=l;i<=r;i++)if(!vis[num[i]])ans++;
cout<<ans<<endl;
}
else{
for(int i=l;i<=r;i++){
p[i-l]=i;
}
for(int i=1;i<=cnt;i++){
for(int j=(l+prim[i]-1)/prim[i]*prim[i];j<=r;j+=prim[i]){
while(p[j-l]%prim[i]==0)num[j-l]++,p[j-l]/=prim[i];
}
}
int ans=0;
for(int i=l;i<=r;i++){
if(p[i-l]>1)num[i-l]++;
if(!vis[num[i-l]])ans++;
}
cout<<ans<<endl;
}
return 0;
}