[ABC206E] Divide Both 解题记录

[ABC206E] Divide Both 解题记录


题意简述

给定整数 L , R L,R L,R,求满足以下条件的数对 ( x , y ) (x,y) (x,y) 的数量。

  • x , y x,y x,y 不互质
  • x ∤ y x \nmid y x∤y 且 y ∤ x y \nmid x y∤x

题目分析

正难则反,考虑用所有的满足第一条性质的数对的数量减去不满足第二条性质的数量。

容易想到,如果不考虑第二条性质,那么我们可以枚举因子 i ∈ [ 2 , r ] i \in [2,r] i∈[2,r],求解出 [ l , r ] [l,r] [l,r] 区间内的 i i i 的倍数的个数 s s s,然后用加法原理,两两配对,累加到答案中。

如何求解 s s s?

不妨设 x = k × i + b x=k \times i+b x=k×i+b,则 i ∣ ( x − b ) i \mid (x-b) i∣(x−b),即对于每个 j ∈ [ 1 , k ] j \in [1,k] j∈[1,k] 都有 i ∣ ( x − b − j × i ) i \mid (x-b-j \times i) i∣(x−b−j×i),一共 k k k 个数,而这个 k k k 就是 ⌊ r i ⌋ \lfloor\frac{r}{i}\rfloor ⌊ir⌋,对于 k k k 个数字两两配对,即可求解出 s = k × ( k − 1 ) 2 s=\frac{k \times (k-1)}{2} s=2k×(k−1)。但是这样会有重复,如:当 i = 2 , 3 , 6 i=2,3,6 i=2,3,6 时,均会有数对 ( 6 , 12 ) (6,12) (6,12),这个时候就需要我们标记了。可以设 c n t i cnt_i cnti 表示 i i i 的质因子的个数,如果 c n t i cnt_i cnti 为偶数,就减去当前贡献,否则加上。那么我们对于 i = 2 , 3 i=2,3 i=2,3 的时候加上了 ( 6 , 12 ) (6,12) (6,12) 的贡献,在 i = 6 i=6 i=6 的时候就会减去一个,这样就保证了贡献不会重复(不清楚的可以手模)。

最后减去不满足第二条限制的贡献:对于每个因子 i ∈ [ 2 , r ] i \in [2,r] i∈[2,r],减去 [ l , r ] [l,r] [l,r] 中除 i i i 外 i i i 的倍数,即: ⌊ r i ⌋ − 1 \lfloor\frac{r}{i}\rfloor -1 ⌊ir⌋−1。


AC Code
cpp 复制代码
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=1e6+5;
int l,r,ans,cnt[N];
void init() {
    rep(i,2,r) {
        if(cnt[i]!=0) {
            continue;
        }
        for(int j=i;j<=r;j+=i) {
            if(cnt[j]>=0) {
                cnt[j]++;
            }
        }
        for(int j=i*i;j<=r;j+=i*i) {
            cnt[j]=-1;
        }
    }
}
signed main() {
    std::cin>>l>>r;
    init();
    rep(i,2,r) {
        if(cnt[i]<0) {
            continue;
        }
        int s=r/i-(l-1)/i;
        s=s*(s-1)/2;
        if(cnt[i]%2) {
            ans+=s;
        } else {
            ans-=s;
        }

    }
    rep(i,std::max(l,2ll),r) {
        ans-=r/i-1;
    }
    std::cout<<ans*2;
    return 0;
}
相关推荐
py有趣20 分钟前
力扣热门100题之和为K的子数组
数据结构·算法·leetcode
hipolymers38 分钟前
C语言怎么样?难学吗?
c语言·数据结构·学习·算法·编程
workflower2 小时前
机器人应用-楼宇室内巡逻
大数据·人工智能·算法·microsoft·机器人·动态规划·享元模式
ZPC82102 小时前
fanuc 机器人通过PR寄存器实现轨迹控制
人工智能·算法·计算机视觉·机器人
py有趣2 小时前
力扣热门100题之编辑距离
数据结构·算法·leetcode
Wave8453 小时前
C++继承详解
开发语言·c++·算法
Tairitsu_H3 小时前
C++类基础概念:定义、实例化和this指针
开发语言·c++
睡觉就不困鸭3 小时前
第9天 两数之和
算法·哈希算法·散列表
不想写代码的星星3 小时前
C++17 string_view 观察报告:好用,但有点费命
c++
贾斯汀玛尔斯3 小时前
每天学一个算法--动态规划(Dynamic Programming, DP)
算法·动态规划