[ABC206E] Divide Both

文章讲述了如何解决一道编程竞赛题目DivideBoth,主要涉及数论中的容斥原理和莫比乌斯函数。首先,将原问题转换为计算满足特定条件的数对(x,y)的数量,然后利用容斥原理分别计算出gcd(x,y)=1,gcd(x,y)=x,gcd(x,y)=y的情况,最后通过减去重复部分得到答案。文章提供了详细的公式推导和AC代码示例。
摘要由CSDN通过智能技术生成

[ABC206E] Divide Both

题意

​ 给定 L ≤ R L \leq R LR,计算出(x,y)的对数满足以下条件:

  • L ≤ x , y ≤ R L \leq x, y \leq R Lx,yR
  • 设g是x,y的最大公约数,满足 g ≠ 1 , x g ≠ 1 , y g ≠ 1 g ≠ 1,\frac{x}{g} ≠ 1,\frac{y}{g} ≠ 1 g=1,gx=1,gy=1

分析

容斥原理

通过题意,可以将其转化为计算公式:
∑ i = L R ∑ j = L R [ g c d ( i , j ) ≠ 1 ] [ g c d ( i , j ) ≠ i ] [ g c d ( i , j ) ≠ j ] \begin{align} \sum_{i=L}^{R}\sum_{j=L}^{R}[gcd(i,j)≠1][gcd(i,j)≠i][gcd(i,j)≠j] \end{align} i=LRj=LR[gcd(i,j)=1][gcd(i,j)=i][gcd(i,j)=j]
其中 L ≤ x ≤ R , L ≤ y ≤ R L \leq x \leq R, L \leq y \leq R LxR,LyR,所以一共的方案数就是 ( R − L + 1 ) 2 (R-L+1)^{2} (RL+1)2
∑ i = L R ∑ j = L R ∑ g = 1 R [ g c d ( i , j ) = g ] = ( R − L + 1 ) 2 \begin{align} \sum_{i=L}^{R}\sum_{j=L}^{R}\sum_{g=1}^{R}[gcd(i,j)=g]=(R-L+1)^{2} \end{align} i=LRj=LRg=1R[gcd(i,j)=g]=(RL+1)2
因此根据容斥原理,我们需要找出三种数

  • g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1
  • g c d ( x , y ) = x gcd(x,y)=x gcd(x,y)=x
  • g c d ( x , y ) = y gcd(x,y)=y gcd(x,y)=y

其中 g c d ( x , y ) = x gcd(x,y)=x gcd(x,y)=x g c d ( x , y ) = y gcd(x,y)=y gcd(x,y)=y可以合并为一种数。因此将方案总数减去每一种数的个数,再加上两种数的交集就是最终的答案数

令总方案数为 S 1 S1 S1 g c d ( x , y ) = 1 gcd(x,y)=1 gcd(x,y)=1方案数为 S 2 S2 S2 g c d ( x , y ) = x gcd(x,y)=x gcd(x,y)=x方案数为 S 3 S3 S3 g c d ( x , y ) = 1 & & g c d ( x , y ) = x gcd(x,y)=1\&\&gcd(x,y)=x gcd(x,y)=1&&gcd(x,y)=x方案数为 S 4 S4 S4,可知答案就是 S 1 − S 2 − S 3 + S 4 S1-S2-S3+S4 S1S2S3+S4

可知总方案数 S 1 = ( R − L + 1 ) 2 S1=(R-L+1)^{2} S1=(RL+1)2

计算 S 2 : g c d ( x , y ) = 1 S2:gcd(x,y)=1 S2:gcd(x,y)=1:
S 2 = ∑ i = L R ∑ j = L R [ g c d ( i , j ) = 1 ] = ∑ i = L R ∑ j = L R ∑ d ∣ x , d ∣ y μ ( d ) = ∑ d = 1 R μ ( d ) ( ⌊ R d ⌋ − ⌊ L + d − 1 d ⌋ + 1 ) 2 = ∑ d = 1 R μ ( d ) ( ⌊ R d ⌋ − ⌊ L − 1 d ⌋ ) 2 \begin{align} S2&=\sum_{i=L}^{R}\sum_{j=L}^{R}[gcd(i,j)=1]\\ &=\sum_{i=L}^{R}\sum_{j=L}^{R}\sum_{d|x,d|y}\mu(d)\\ &=\sum_{d=1}^{R}\mu(d)(\lfloor \frac{R}{d} \rfloor-\lfloor \frac{L+d-1}{d} \rfloor+1)^{2}\\ &=\sum_{d=1}^{R}\mu(d)(\lfloor \frac{R}{d} \rfloor-\lfloor \frac{L-1}{d} \rfloor)^{2} \end{align} S2=i=LRj=LR[gcd(i,j)=1]=i=LRj=LRdx,dyμ(d)=d=1Rμ(d)(⌊dRdL+d1+1)2=d=1Rμ(d)(⌊dRdL1)2
若看不懂莫比乌斯函数的转化,可以参考帮助理解

计算 S 3 : g c d ( x , y ) = x S3:gcd(x,y)=x S3:gcd(x,y)=x:

可知在 [ L , R ] [L,R] [L,R]中为任意一个数 z z z的倍数的个数为 ⌊ R z ⌋ − ⌊ L + z − 1 z ⌋ + 1 \lfloor \frac{R}{z} \rfloor - \lfloor \frac{L+z-1}{z} \rfloor+1 zRzL+z1+1

[ 1 , R ] [1,R] [1,R]中为任意一个数 z z z的倍数的个数为 ⌊ R z ⌋ \lfloor \frac{R}{z} \rfloor zR
S 3 = ∑ x = L R ⌊ R x ⌋ + ∑ y = L R ⌊ R y ⌋ − ( R − L + 1 ) = 2 ∑ x = L R ⌊ R x ⌋ − ( R − L + 1 ) \begin{align} S3&=\sum_{x=L}^{R}\lfloor \frac{R}{x} \rfloor+\sum_{y=L}^{R}\lfloor \frac{R}{y} \rfloor-(R-L+1)\\ &=2\sum_{x=L}^{R}\lfloor \frac{R}{x} \rfloor-(R-L+1) \end{align} S3=x=LRxR+y=LRyR(RL+1)=2x=LRxR(RL+1)
其中 ( R − L + 1 ) (R-L+1) (RL+1)指的是重复计算的 x = y x=y x=y的部分

计算 S 4 : g c d ( x , y ) = 1 & & g c d ( x , y ) = x S4:gcd(x,y)=1\&\&gcd(x,y)=x S4:gcd(x,y)=1&&gcd(x,y)=x

不难发现,当 L = 1 L=1 L=1时,x和y中必定至少有一个是1,这种情况下才需要计算 S 4 S4 S4,否则不需要计算,因为 x , y x,y x,y根本取不到1,因此只需要计算出 x = 1 x=1 x=1 y = 1 y=1 y=1时的方案数,减去 x = 1 , y = 1 x=1,y=1 x=1,y=1的方案数即可
S 4 = 2 ( R − L + 1 ) − 1 \begin{align} S4=2(R-L+1)-1 \end{align} S4=2(RL+1)1
最终答案ans:
a n s = S 1 − S 2 − S 3 + [ L = 1 ] S 4 \begin{align} ans=S1-S2-S3+[L=1]S4 \end{align} ans=S1S2S3+[L=1]S4

AC代码

#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int prime[1000010], cnt, mobius[1000010];
bool vis[1000010];
void init() {
    mobius[1] = 1;
    for (int i = 2; i <= 1000000; i++) {
        if (!vis[i]) {
            prime[++cnt] = i;
            mobius[i] = -1;
        }
        for (int j = 1; j <= cnt && i * prime[j] <= 1000000; j++) {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0) {
                break;
            }
            mobius[i * prime[j]] = -mobius[i];
        }
    }
}
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    init();
    int l, r;
    cin >> l >> r;
    LL ans = 1LL * (r - l + 1) * (r - l + 1);
    for (int d = 1; d <= r; d++) {
        ans = ans - 1LL * mobius[d] * (r / d - (l - 1) / d) * (r / d - (l - 1) / d);
    }
    for (int d = l; d <= r; d++) {
        ans = ans - 1LL * (r / d) * 2;
    }
    ans = ans + r - l + 1;
    if (l == 1) {
        ans = ans + 2 * (r - l + 1) - 1;
    }
    cout << ans << '\n';
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值