LJJ 爱数数 输入 n n n,输出三个数均不超过 n n n, gcd ( a , b , c ) = 1 \gcd(a,b,c)=1 gcd(a,b,c)=1 且 1 a + 1 b = 1 c \dfrac 1 a+\dfrac 1 b=\dfrac 1 c a1+b1=c1 的组 ( a , b , c ) (a,b,c) (a,b,c) 个数。
反演。 由于 0xis 显然不会做,以下转载原题解。非常害怕 NOIP D1T1 考此等。
考虑
q
=
gcd
(
a
,
b
)
,
a
=
A
q
,
b
=
B
q
q=\gcd(a,b),a=Aq,b=Bq
q=gcd(a,b),a=Aq,b=Bq,因
c
=
a
b
a
+
b
=
q
A
B
A
+
B
c=\dfrac{ab}{a+b}=q\dfrac{AB}{A+B}
c=a+bab=qA+BAB。
因
gcd
(
a
,
b
,
c
)
=
1
\gcd(a,b,c)=1
gcd(a,b,c)=1 故
gcd
(
q
,
c
)
=
1
\gcd(q,c)=1
gcd(q,c)=1,因
q
∣
(
A
+
B
)
c
q|(A+B)c
q∣(A+B)c 故
q
∣
(
A
+
B
)
q|(A+B)
q∣(A+B)。
令
p
=
A
+
B
q
=
A
B
c
p=\dfrac{A+B}{q}=\dfrac{AB}{c}
p=qA+B=cAB,有
p
=
1
p=1
p=1 (否则
p
∣
A
p|A
p∣A 或
p
∣
B
p|B
p∣B,故
p
̸
∣
A
B
p\not | AB
p̸∣AB)。
故
c
=
a
b
q
2
,
a
+
b
=
q
2
c=\dfrac{ab}{q^2} ,a+b=q^2
c=q2ab,a+b=q2,此时
q
∈
[
1..
2
n
]
q\in [1..\sqrt{2n}]
q∈[1..2n]。一定范围内与
q
q
q 互质数数量即为合法解数。
范围为 [ max { 1 , q 2 − n } q , min { q 2 − 1 , n } q ] [\dfrac{\max\{1,q^2 -n\}}q,\dfrac{\min\{q ^2-1,n\}}q] [qmax{1,q2−n},qmin{q2−1,n}],原文未解释。事实上,因 a + b = q 2 , a , b ≤ n a+b=q ^2,a,b\le n a+b=q2,a,b≤n,故 a b ∈ [ q 2 − n , q 2 − 1 ] ab\in[q ^2 -n,q ^2-1] ab∈[q2−n,q2−1]。
#include <cstdio>
#include <cmath>
#include <algorithm>
#define F(z, u, v) for(int z = (u), dest##z = (v); z <= dest##z; ++z)
typedef long long LINT;
const int MAXG = 20000001, MAXM = 2000001;
LINT n, ans = 0;
namespace Tot {
int mu[MAXM] = {0, 1}, hd[MAXM], po[MAXG], dt[MAXG], gn, zl[MAXM], zn;
bool hs[MAXM];
void GetMu() {
F(i, 2, MAXM - 1) { if(!hs[i]) zl[++zn] = i, mu[i] = -1;
F(j, 1, zn) { if(i * zl[j] >= MAXM) break; hs[i * zl[j]] = true;
if(!(i % zl[j])) break; mu[i * zl[j]] = -mu[i]; }}}
void GetYs() {
F(i, 1, MAXM - 1) if(mu[i]) for(int j = i; j < MAXM; j += i)
po[++gn] = hd[j], dt[gn] = i, hd[j] = gn; }
int Btw(int n, int m) {
int re = 0; if(m <= 0) return 0;
for(int i = hd[n]; i; i = po[i]) re += m / dt[i] * mu[dt[i]];
return re; }}
int main() {
Tot::GetMu(); Tot::GetYs(); scanf("%lld", &n);
F(i, 1, std::sqrt(n << 1))
ans -= Tot::Btw(i, (std::max(1ll, LINT(i) * i - n) - 1) / i)
- Tot::Btw(i, std::min(LINT(i) * i - 1, LINT(n)) / i);
printf("%lld", ans); return 0; }