不可整除的数字

Number that are not divisible

本文关键字:数字      更新时间:2023-10-16

你会得到一个正整数N。你的任务是找到正整数 K ≤ N 的数量,使得 K 不能被集合 {2,3,4,5,6,7,8,9,10} 中的任何数字整除。

我在想所有的素数,但它没有给出正确的答案。

令人惊讶的是,答案非常简单。

#include <iostream>
using namespace std;
int main() {
    int t;
    cin>>t;
    while(t--) {
        long long n;
        cin>>n;
        long long ans = (n/2+n/3+n/5+n/7)-(n/6+n/10+n/14+n/15+n/21+n/35)+(n/30+n/42+n/70+n/105)-(n/210);
        cout<<n - ans<<endl;
    }
    return 0;
}

但我不明白这个算法。谁能给我解释一下这个算法。

集合中的素数是 2、3、5 和 7。使用这些,我们计算:

how many numbers up to N are divisible by 2, 3, 5 and 7

但后来我们高估了可被两者整除的数字:

2,3 = 6
2,5 = 10
2,7 = 14
etc.

但随后我们过度减去所有可被所有三个数字整除的数字:

2,3,5 = 30
2,3,7 = 42
etc.

等。。。

这种组合原理称为包含-排除。

这个过程之后剩下的任何东西都不能被这些素数整除。(请注意,如果一个数字不能被 2 整除,则它不能被 4、6、8 和 10 整除;3 和 9 也是如此。

首先,计算集合中不能被素数整除的数字。

  • n/2个数字不能被 2 整除。
  • n/3的数字不能被 3 整除。
  • 等。

但是,有些数字被计算了两次。不能被 6 整除的数字既不能被 2 整除,也不能被 3 整除,所以我们从总数中减去它们。

像 30 这样的数字在第一阶段被计算三次(作为 2、3 和 5 的倍数(,但在第二阶段被计算了三次(作为 6、10 和 15 的倍数(。因此,我们必须再次将它们相加,净贡献为 1。

因此,最终答案中的每个括号表达式表示计算集合中不能被数字整除的数字,或者补偿先前的高计数或少计数。

存在非递归解决方案。

int N = ....; 
int const primes[4] = {2,3,5,7};
int result = 0;
for(int i = 0; i < 16; ++i)// 16 = 2^4
{ 
    int p = 1, s = 1; // s = (-1)^bits(i).
    for(int j = 0; j < 4; ++j)
        if ( ( i >> j ) & 1 ) 
            p *= primes[j], s *= -1;
    result += (N / p) * s; 
}