题目相关
题目链接
AtCoder Beginner Contest 170 D题,https://atcoder.jp/contests/abc170/tasks/abc170_d。
Problem Statement
Given is a number sequence A of length N.
Find the number of integers i (1 ≤ i ≤ N) with the following property:
- For every integer j (1 ≤ j ≤ N) such that i≠j, Aj does not divide Ai.
Input
Input is given from Standard Input in the following format:
N
A1 A2 ... AN
Output
Print the answer.
Samples1
Sample Input 1
5
24 11 8 3 16
Sample Output 1
3
Explaination
The integers with the property are 2, 3, and 4.
Samples2
Sample Input 2
4
5 5 5 5
Sample Output 2
0
Explaination
Note that there can be multiple equal numbers.
Samples3
Sample Input 3
10
33 18 45 28 8 19 89 86 2 4
Sample Output 3
5
Constraints
- All values in input are integers.
- 1 ≤ N ≤ 2×10^5
- 1 ≤ Ai ≤ 10^6
题解报告
题目翻译
各一个数列 A 及长度 N。要求我们找出符合以下条件的整数 i。
- 对于每一个整数 j,当 i≠j 的时候,Aj 不能被 Ai 整除。
样例数据分析
样例数据 1
根据样例,N=5,对应的数列 A 为 {24 11 8 3 16}。开始的时候 ans = 0。
1、经过排序后,数列变为 {3 8 11 16 24}。
2、数据 3。第一个元素,而且只出现一次,所以 ans = 1。
3、数据 8。前面的所有元素 {3} 都不是 8 的质因数。所以 ans = 2。
4、数据 11。前面的所有元素 {3 8} 都不是 11 的质因数。所以 ans = 3。
5、数据 16。前面的所有元素 {3 8 11} 中,16%8=0。所以 ans = 3。
6、数据 24。前面的所有元素 {3 8 11 16} 中,24%8=0。所以 ans = 3。
样例数据 2
根据样例,N=4,对应的数列 A 为 {5 5 5 5}。开始的时候 ans = 0。
1、经过排序后,数列变为 {5 5 5 5}。
2、数据 5。第一个元素,而且只出现多次,所以 ans = 0。
3、数据 5。前面的所有元素 {5} 中,5%5=0。所以 ans = 0。
4、数据 5。前面的所有元素 {5 5} 中,5%5=0。所以 ans = 0。
5、数据 5。前面的所有元素 {5 5 5} 中,5%5=0。所以 ans = 0。
样例数据 3
根据样例,N=10,对应的数列 A 为 {33 18 45 28 8 19 89 86 2 4}。开始的时候 ans = 0。
1、经过排序后,数列变为 {2 4 8 18 19 28 33 45 86 89}。
2、数据 2。第一个元素,而且只出现一次,所以 ans = 1。
3、数据 4。前面的所有元素 {2} 中,4%2=0。所以 ans = 1。
4、数据 8。前面的所有元素 {2 4} 中,8%2=0。所以 ans = 1。
5、数据 18。前面的所有元素 {2 4 8} 中,18%2=0。所以 ans = 1。
6、数据 19。前面的所有元素 {2 4 8 18} 都不是 19 的质因数。所以 ans = 2。
7、数据 28。前面的所有元素 {2 4 8 18 19} 中,28%2=0。所以 ans = 2。
8、数据 33。前面的所有元素 {2 4 8 18 19 28} 都不是 33 的质因数。所以 ans = 3。
9、数据 45。前面的所有元素 {2 4 8 18 19 28 33} 都不是 45 的质因数。所以 ans = 4。
10、数据 86。前面的所有元素 {2 4 8 18 19 28 33 45} 中,86%2=0。所以 ans = 4。
11、数据 89。前面的所有元素 {2 4 8 18 19 28 33 45 86} 都不是 89 的质因数。所以 ans = 5。
题目分析
从上面的样例数据分析中,我们可以发现,本题最核心的就是如何找整除关系。
很多人马上能想到一个最朴素的算法,如下所示。
for (int i=1; i<=n; i++) {
for (int j=1; j<i; j++) {
在循环里判断a[i]和a[j]的关系
}
}
我们要注意的是,上面的算法复杂度为 ,从本题的数据范围看,必然结果是 TLE。
如何优化这部分呢?我们可以换一个角度看这个问题,将问题变为找出数据 a[i] 在题目规定的数据范围内的所有倍数即可。这样我们将 的复杂度变成了 O(n)。代码如下所示。
for (int i=1; i<=n; i++) {
for (int j=1; a[i]*j<=1e6; j++) {
这里标志所有的倍数关系
}
}
如上的代码,算法的复杂度是 O(n)。因为循环内嵌的循环是常数级别。
本题也是一个模板题。基本的思路就是排序后,再筛一下就可以。
数据规模分析
N 的最大值为 2e5。Ai 最大值为 1e6。因此本题最高的算法复杂度不能超过 O(nlogn)。
算法设计
1、读取数据。
2、排序。
3、在 1e6 的数据范围内,标注出所有 a[i] 的倍数。
TLE 代码
#include <cstdio>
#include <algorithm>
#include <map>
using namespace std;
const int MAXN = 2e5+2;
int main() {
int n;
scanf("%d", &n);
map<int, int> m;
for (int i=0; i<n; i++) {
int data;
scanf("%d", &data);
m[data]++;
}
int ans = 0;
bool flag = false;
map<int, int>::iterator it1;
map<int, int>::iterator it2;
for (it1=m.begin(); it1!=m.end(); it1++) {
if (1==it1->second) {
for (it2=m.begin(); it2!=it1; it2++) {
flag = false;
if (0==it1->first % it2->first) {
flag = true;
break;
}
}
if (false==flag) {
ans++;
}
}
}
printf("%d\n", ans);
return 0;
}
AC 参考代码
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2e5+4;
int a[MAXN];//保存输入数据
const int MAXM = 1e6;
bool flag[MAXM+4];//倍数标志
int main() {
int n;
scanf("%d", &n);
for (int i=1; i<=n; i++) {
scanf("%d", &a[i]);
}
sort(a+1, a+n+1);
int ans = 0;
for (int i=1; i<=n; i++) {
if (false==flag[a[i]]) {
if (a[i]!=a[i+1]) {
//参考样例2
ans++;
}
for (int j=1; a[i]*j<=MAXM; j++) {
flag[a[i]*j] = true;
}
}
}
printf("%d\n", ans);
return 0;
}