題目相關
題目鏈接
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;
}