新千题计划 6#:[洛谷 4844] LJJ 爱数数

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 pA p ∣ B p|B pB,故 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,q2n},qmin{q21,n}],原文未解释。事实上,因 a + b = q 2 , a , b ≤ n a+b=q ^2,a,b\le n a+b=q2,a,bn,故 a b ∈ [ q 2 − n , q 2 − 1 ] ab\in[q ^2 -n,q ^2-1] ab[q2n,q21]

#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; }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值