URAL 2070 Interesting Numbers (因子个数 + 逆向思维)

传送门:URAL 2070



题目大意:

有两个条件:

1. 数为素数

2. 数的因子个数为素数


求区间 [ L , R ] 中同时满足或同时不满足以上两条的数的个数。



扫描二维码关注公众号,回复: 1755629 查看本文章

思路:

因为区间最大 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;
}

猜你喜欢

转载自blog.csdn.net/zuzhiang/article/details/80145408