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;
}

 

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