[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;
}
相关推荐
wydaicls1 小时前
C语言对单链表的操作
c语言·数据结构·算法
傻童:CPU1 小时前
C语言需要掌握的基础知识点之排序
c语言·算法·排序算法
骁的小小站3 小时前
Verilator 和 GTKwave联合仿真
开发语言·c++·经验分享·笔记·学习·fpga开发
大数据张老师5 小时前
数据结构——邻接矩阵
数据结构·算法
低音钢琴6 小时前
【人工智能系列:机器学习学习和进阶01】机器学习初学者指南:理解核心算法与应用
人工智能·算法·机器学习
旭意6 小时前
C++蓝桥杯之结构体10.15
开发语言·c++
深思慎考7 小时前
调用百度云语音识别服务——实现c++接口识别语音
c++·语音识别·百度云
傻童:CPU8 小时前
C语言需要掌握的基础知识点之前缀和
java·c语言·算法
又见野草8 小时前
软件设计师知识点总结:数据结构与算法(超级详细)
数据结构·算法·排序算法
GalaxyPokemon8 小时前
有一个服务器,用于提供HTTP服务,但是需要限制每个用户在任意的100秒内只能请求60次,怎么实现这个功能
算法