AtCoder Beginner Contest 170 D题,https://atcoder.jp/contests/abc170/tasks/abc170_d。
Given is a number sequence A of length N.
Find the number of integers i (1 ≤ i ≤ N) with the following property:
Input is given from Standard Input in the following format:
N
A1 A2 ... AN
Print the answer.
5
24 11 8 3 16
3
The integers with the property are 2, 3, and 4.
4
5 5 5 5
0
Note that there can be multiple equal numbers.
10
33 18 45 28 8 19 89 86 2 4
5
各一个数列 A 及长度 N。要求我们找出符合以下条件的整数 i。
根据样例,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。
根据样例,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。
根据样例,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
我们要注意的是,上面的算法复杂度为 ,从本题的数据范围看,必然结果是 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] 的倍数。
#include
#include
#include
#include
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;
}