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;
}
posted @ 2023-11-13 11:46  Candycar  阅读(8)  评论(0)    收藏  举报