传送门:URAL 2070
题目大意:
有两个条件:
1. 数为素数
2. 数的因子个数为素数
求区间 [ L , R ] 中同时满足或同时不满足以上两条的数的个数。
思路:
因为区间最大 1e12,无法求出素数的个数,所以考虑该问题的互斥事件,然后用总个数减去互斥事件个数即结果。互斥事件即上面的两个条件只满足一条:
1. 数为素数,但是数的因子个数不为素数
2. 数为合数,但是数的因子个数为素数
以上条件满足其一即可,先看第一条:数为素数时,因子只有 1 和其本身,数的因子个数为 2,是素数。不满足第一条。
第二条,易知除了平分数之外其它数的因子个数都是成对出现,而要想使得因子个数为素数,则因子个数一定是奇数。所以我们只要找平分数中因子个数为素数的数的个数即可。
由唯一分解定理可知,某个数 n 可以唯一分解为 n = p1^a1 + p2^a2 + …… +pn^an,而其因子个数 num = (a1+1)*(a2+1)*……*(an+1)。
num如果是素数,则只应该含有除 1 之外的一个因子,所以 n = p^a,即 n 只能有 1 个质因子。又因为我们要找的 n 是平方数,所以 a 也一定是偶数。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
int tol,pri[1000010],p[80000];
void init()
{ //打素数表
int i,j;
tol=0;
memset(pri,1,sizeof(pri));
for(i=2;i<1000010;i++)
if(pri[i])
{
p[tol++]=i;
for(j=i*2;j<1000010;j+=i) pri[j]=0;
}
}
int main()
{
LL i,j,l,r,x,tmp,cnt,ans;
init();
while(~scanf("%lld%lld",&l,&r))
{
ans=r-l+1;
for(i=0;i<tol;i++)
{ //对有每个素数
x=(LL)p[i]*p[i]; //当前素数的平方
if(x>r) break; //如果当前素数形成的平方数不在所求区间内
cnt=2; //即 p^cnt
tmp=x;
for(;tmp<=r;tmp*=x,cnt+=2)
{ //tmp每次增大的平方数,指数cnt每次+2
if(tmp<l) continue; //如果不在区间内
//因为只有一个质因子,其因子个数为 cnt+1 个
if(pri[cnt+1]) ans--; //如果该平方数是素数则结果 -1
}
}
printf("%lld\n",ans);
}
return 0;
}