不可分割的数字

时间:2018-01-04 17:17:51

标签: c++ algorithm

你将得到一个正整数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;
}

但我不明白这个算法。任何人都可以解释这个算法。

3 个答案:

答案 0 :(得分:7)

集合中的素数是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.

等...

这种组合原则称为inclusion-exclusion

在这个过程之后留下的任何东西都不能被那些素数整除。 (请注意,如果一个数字不能被2整除,则它不能被4,6,8和10整除; 3和9则相同。)

答案 1 :(得分:1)

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

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

然而,一些数字被计算两次。不能被6整除的数字不能被2和3整除,所以我们从总数中减去它们。

在第一阶段(如2,3和5的倍数),像30这样的数字计算次,但在第二阶段计算三次次阶段(作为6,10和15的倍数)。所以我们必须再次将它们添加到 中,净贡献为1。

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

答案 2 :(得分:0)

存在非递归解决方案。

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; 
}
相关问题