# [省选联考 2021 B 卷] 数对

发布时间 2023-12-11 18:55:05作者: xinyimama

题目描述

给定 \(n\) 个正整数 \(a_i\),请你求出有多少个数对 \((i, j)\) 满足 \(1 \le i \le n\)\(1 \le j \le n\)\(i \ne j\)\(a_i\)\(a_j\) 的倍数。

输入格式

第一行,一个整数 \(n\),表示数字个数。
第二行,\(n\) 个整数,表示 \(a_i\)

输出格式

输出一行,一个整数,表示答案。

样例 #1

样例输入 #1

6
16 11 6 1 9 11

样例输出 #1

7

样例 #2

样例输入 #2

见附件中的 pair/pair2.in。

样例输出 #2

见附件中的 pair/pair2.ans。

提示

对于 \(40 \%\) 的数据,\(n \le 1000\)
对于 \(70 \%\) 的数据,\(1 \le a_i \le 5 \times {10}^3\)
对于 \(100 \%\) 的数据,\(2 \le n \le 2 \times {10}^5\)\(1 \le a_i \le 5 \times {10}^5\)

题解

对于这道题而言,我们首先想到的是枚举i和j,但是这样的枚举时间复杂度是\(O(n^2)\),根本过不去

根据套路,遇到约数问题,我们首先想到倍数问题,所以对于每个数,我们枚举他的倍数,同时将每个数存在桶里,这样就可以了,但是如果有1的话,所有的数都是他的倍数,所以1单独处理,同时1倍关系就是自己本身,所以也是单独处理

点击查看代码
for(int i=1;i<=n;i++){
        if(a[i]==1) continue;
        for(int k=2;k<=mx/a[i];k++)
            if(b[k*a[i]]) ans+=b[k*a[i]];
这样的代码,我过了这个题,但是我觉得这个时间复杂度是不对的,那这个时间复杂度具体是怎么分析呢?

这么分析,我么可以借鉴埃氏筛的时间复杂度分析,这个题简化起来,对于每一个小于等于mx的数,将其所有的倍数枚举一遍,时间复杂度为\(O(\sum_{i=1}^{n}\frac{mx}{a[i]})\),这样的时间复杂度为\(O(mxlog{mx})\),但是有一个前提是这些数都各不相同,如果都相同的话就不行,比如有1000个数字,前面都是2,最后一个数字是1000,这样的时间复杂度就是错的,所以我们在这样做之前,需要去重

这道题对我来说,最大的启示是时间复杂度的分析,当时没有想到埃氏筛相关,同时对去重的问题,之前也不知道。