本文章为原创文章,未经过允许不得转载
运行要求
运行时间限制: 2sec
内存限制: 1024MB
原题链接

题目
给定一长度为N的字符串A
求满足下面特性的整数i的个数(1<=i<=N)

  • 对于i!=j的任意整数j(1<=j<=N),要求Ai不能够被Aj整除

输入前提条件

  • 所有的输入均为整数
  • 1<=N<=2*100000
  • 1<=Ai<=1000000

输入
输入按照以下形式标准输入

N
A1 A2 A3 ... AN

输出
直接输出结果


例1
输入

5
24 11 8 3 16

输出
3

满足条件的i为2,3,4
11,8,3满足条件,不能被其他的数整除

例2
输入

4
5 5 5 5

输出

0

注意相同数存在的情况

例3
输入

10
33 18 45 28 8 19 89 86 2 4

输出

5

读懂题目
给定一串数,然后找出这里面不能被其他数整除的数
比如例1中给出的
24 11 8 3 16
24可以背11整除
16可以被8整除
所以24,16都不满足条件
11,8,3不能被字符串中除了自己以外其余的数整除,所以满足条件

解题思路
最原始的思路就是,遍历字符串N当中的每一个字符Ai,然后再遍历剩余的字符Aj,看看Ai%Aj==0与否。
这样的复杂度是N^2,但是N<=2*100000
所以时间上是不用许的
D问题也不会这么简单

这一题有点像之前做过的
https://segmentfault.com/a/1190000022856382
这道题通过素数筛选法(英文叫sieve of Eratosthenes)来手写2到100000的素数
思路就是,确定一个低位数组的范围,确定一个高位数组的额范围
通过对低位素数A的遍历,筛选出高位数组中A的倍数,剩下的没有被筛选到的就是需要的数字

ABC 84D的低位数组范围是2-sqrt(N)
高位数组范围是2-N

这一题也可以用同样的思路去求解
给定了字符串N
1<=N<=2*100000
我们遍历一遍,复杂度是O(N),时间上是允许的

Ai的最大值是1000000
那么,我们的低位数组范围限定为1-N
高位数组范围限定为1-2*100000+6

遍历低位数组(1-N),每遍历到Ai,刷选出高位数组中Ai的倍数做标记。
剩下的高位数组当中仅被标记过一次,切属于低位数组就是满足条件的

名称未設定.001.jpeg
我们以例1为例子
给定的低位数组是{24,11,8,3,16}
高位数是1到1000006

名称未設定.002.jpeg
对于高位数组,初始标记为0

名称未設定.003.jpeg
开始遍历低位数组
遍历到24
开始找高位数组中24的倍数{24,48,72....}
给他们的标记+1

名称未設定.004.jpeg
同理遍历低位数组的11
找高位数组中11的倍数{11,22,33,44....}
给他们的标记+1

名称未設定.005.jpeg
同理遍历低位数组的8

名称未設定.006.jpeg
同理遍历低位数组的3

名称未設定.007.jpeg
遍历低位数组的16
这里要注意一下,当遍历到高位数组中的某一个元素的时候,如果发现它的标记不为0,说明它是已遍历过的低位数组元素的其中一位的倍数
比如这个时候遍历到高位数组的16的时候,发现他的标记为1(因为已经被低位数组中的8的倍数标记过了)
这个时候没有必要继续在高位数组中找16的倍数了
因为16的倍数32,48也是8的倍数
16 X n = 8 X 2n
这个时候要取消高位数组查找倍数的操作
这个取消操作很重要,不加的话也会得出正确答案,但是会超时

名称未設定.008.jpeg
最终得到标记好的高位数组
高位数组中标记为1的代表该高位数组元素是低位数组中有且仅有一位的元素的倍数

但是我们要找的是高位数组标记为1,并且倍数也是1的
其实就是要找低位数组当中元素在高位数组当中标记为1的元素

代码

N = int(input())
ARR = list(map(int,input().split()))

def calculate(n, arr):
    krr = [0 for i in range(1, 1000007)]

    for i in range(n):
        start = arr[i]

        if krr[start] > 0: ### 这里不加的话,结果正确但是回超时
            krr[start] = 2
            continue

        for j in range(start, 1000006, start):
            krr[j] += 1

    result = 0
    for i in range(n):
        if krr[arr[i]] == 1:
            result += 1

    print(result)


calculate(N, ARR)
        for j in range(start, 1000006, start):
            krr[j] += 1

这里谈一下为什么是+=1 而不是=1

如果是=1的话
比如我们的低位数组中,有一个16,有一个8
先遍历低位数组的16
高位数组中的16,32,48...被标记为1
后来遍历低位数组红的8
高位数组中的8,16,32,48...被标记为1
这样16的标记为1,且在低位数组中,满足条件,这显然不对

总结
这题考察了对素数筛选法的理解和应用

※ 另外,我会在我的微信个人订阅号上推出一些文章,欢迎关注
二维码.jpg



伟大不DIAO
1 声望1 粉丝

Done is better than perfect