CF1423K Lonely Numbers
思路
因为对于 \(\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
}