CF1423K Lonely Numbers

发布时间 2023-08-27 10:43:19作者: One_JuRuo

思路

因为对于 \(\gcd(a,b)\)\(\frac a{\gcd(a,b)}\)\(\frac b{\gcd(a,b)}\)\(a\)\(b\) 是等价的,可以交换的。所以我们先令 \(a>b\)

\(\gcd(a,b)=d\),因为 \(\frac a{\gcd(a,b)}\) 有除法,所以我们应该想办法去除除法,就同乘以一个 \(d\),即 \(d^2\)\(a\)\(b\) 三条边。

构成三角形的三条边需要满足两条较小边之和大于最大边。

讨论一下情况:

  • \(d^2\) 最大,则需要满足 \(a+b>d^2\)

  • \(d^2\) 不是最大,则 \(a\) 最大,需要满足 \(d^2+b>a\)

如果 \(a,b\) 互质,则 \(d=1\),因为 \(a>b\),所以一定不满足,这种情况一定不能构成三角形。

那么 \(a,b\) 一定不能互质,若 \(d<\sqrt a\),则需要满足 \(d^2+b>a\),令 \(a=d\times k\),只需要令 \(b=d\times (k-1)\),那么就可以满足条件了,若 \(d>\sqrt a\),则需要满足 \(a+b>d^2\),同样是上面一种的构造方法,所以如果 \(a\) 是合数,很容易就能构造满足条件的 \(b\)。所以合数一定不是孤独数字。

再考虑 \(a\) 是质数的情况,这种情况下,\(a\) 没法找到不互质的 \(b\),那么是质数就一定是孤独数字吗?不见得,因为 \(b\) 可以是质数,那么 \(a\) 至少取多少呢?

\(b\)\(k\) 倍吗?三条边就是 \(b\)\(k\times b\)\(b^2\),若 \(k<b\),则需要满足 \(b+k\times b>b^2\) 显然不满足,\(k\) 至少要选 \(b\) 也就是 \(a\) 至少为 \(b^2\)

所以对于质数 \(p\),如果 \(p^2\) 在范围 \([1,n]\) 内,它就不是孤独数字。

所以固定了范围为 \(n\) 后,孤独数字就只有 \(\lfloor \sqrt n\rfloor \sim n\) 的质数了。

所以,可以先线性筛预处理,然后前缀和统计质数个数,最终答案是 \(1\sim n\) 的质数个数减去 \(1\sim \lfloor \sqrt n\rfloor\) 的质数个数,记得加上 \(1\) 的情况,\(1\) 与任意数互质,所以它一定是孤独数字。

AC code

#include<bits/stdc++.h>
using namespace std;
int shu[1000005],pri[1000005],cnt;
int T,n;
inline void init()//线性筛预处理
{
	for(int i=2;i<=1000000;++i)
	{
		if(!shu[i]) pri[++cnt]=i;
		for(int j=1;j<=cnt&&pri[j]*i<=1000000;++j)
		{
			shu[pri[j]*i]=1;
			if(i%pri[j]==0) break;
		}
	}
	for(int i=2;i<=1000000;++i) shu[i]^=1,shu[i]+=shu[i-1];//前缀和统计1~i的质数个数
}
int main()
{
	init();
	scanf("%d",&T);
	while(T--) scanf("%d",&n),printf("%d\n",shu[n]-shu[(int)sqrt(n)]+1);//注意:无论如何1都会孤独数字,所以记得+1
}