AtCoder题解——Beginner Contest 170——D - Not Divisible

题目相关

题目链接

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]的关系
		}
	}

我们要注意的是,上面的算法复杂度为 O(n^{2}),从本题的数据范围看,必然结果是 TLE。

如何优化这部分呢?我们可以换一个角度看这个问题,将问题变为找出数据 a[i] 在题目规定的数据范围内的所有倍数即可。这样我们将 O(n^{2}) 的复杂度变成了 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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章