如何快速判断一个“未知”数字是否可以被3整除?

时间:2017-11-22 15:30:11

标签: math division

我正在努力解决时间限制非常低(1秒)的问题,并且案件数量应该很高。

您需要判断一个数字是否可以被3整除,但问题是您没有得到直接数字,您得到的数字 k ,然后需要检查如果从1到k( 123 ... k )的数字串联可以被3整除。

示例输入:

4  // The number of cases
2
6
15
130000000

输出:

YES  // Because 12 is divisible by 3
YES  // Because 123456 is divisible by 3
YES  // Because 123456789101112131415 is divisible by 3
NO

我发现了一些关于快速检查可分性的主题,但我认为大部分时间都是建立数字。有些情况下,初始数字高达130000000(所以最终的数字是1234 ... 130000000),我认为它会溢出任何数字数据类型。

那么,我在这里错过了什么? 有什么方法可以知道某些东西是否可以被3整除而不会连接数字?有什么想法吗?

PD:有人还发布了三角数公式,这也是一个正确的解决方案然后删除了答案,它是:

if ((1 + num) * num / 2) % 3 == 0 ? "YES" : "NO"

7 个答案:

答案 0 :(得分:10)

  1. 每三个数字可以被三整除。
  2. 每个可被3整除的数字都有一个可被3整除的数字和。
  3. 每三个数字都有一个可被3整除的数字。
  4. 在这些之间,每三个数字的数字总和为1,然后是2 mod 3.
  5. 看看:

    n    digit sum mod 3
    0    0
    1    1
    2    2
    3    0
    4    1
    5    2
    6    0
    ...
    10   1
    11   2
    12   0
    ...
    19   1
    20   2
    21   0
    ...
    

    假设我们有一个按照你描述的方式构造的数字字符串,我们刚刚添加的数字是可分的mod 3.当我们追加下一个数字的数字时,我们附加的数字的总和与1 mod 3相同,并且当添加时对于我们号码中的那些人,我们将得到一个总和为1 mod 3的数字总和,所以我们对下一个的答案将是“否”。下一个将添加一个数字总和为2 mod 3的数字,这导致总数再次变为0,所以答案是“是”。最后,添加必须可被3整除的下一个数字使数字总和保持为0。

    外卖?

    • 如果n与0模3一致,那么答案是“是”
    • 如果n与1模3一致,那么答案是“否”
    • 如果n与2模3一致,则答案为“是”

    特别是,n = 15的例子是错误的;获得的数字字符串代表一个应该可以被3整除的数字,实际上它是(在足够大的计算器上进行验证)。

    剩下的就是找到一个足够快的实现并处理所有必需的案例。如果n保证在20亿以下,那么你可能很安全,比如

    return (n % 3) != 1;
    

    如果n可以是任意大数,那就不要害怕;您可以通过将线性时间中的数字相加来检查数字和是否与0模3一致。如果没有,您可以通过编码添加从数字中添加1,就像在纸上手工添加一样,然后再次以线性时间检查该结果的可分性3。如下所示:

    if (digit_sum_mod_3(n) == 0) return true;
    else if (digit_sum_mod_3(add_one(n)) == 0) return false;
    else return true;
    

    然后你会有像

    这样的东西
    digit_sum_mod_3(n[1...m])
        sum = 0
        for k = 1 to m do
            sum = sum + n[k]
            // keep sum from getting too big
            if sum >= 18 then
                sum = sum - 18
        return sum % 3
    
    add_one(n[1...m])
        // work from right to left, assume big-endian
        for k = m to 1 do
            if n[k] < 9 then // don't need to carry
                n[k] = n[k] + 1
                break
            else then // need to carry
                n[k] = 0
        if n[1] = 0 then // carried all the way to the front
            n[1] = 1
            n[m+1] = 0
        return n
    

答案 1 :(得分:8)

任何三个连续数字总和为0 == a + a + 1 + a + 2 mod 3。 答案减少到k%3 == 0,或2k-1%3 == 0.后者相当于k%3 == 2,这就省去了k%3 == 1,然后进一步简化为{{1 }}

答案 2 :(得分:6)

数学中的一个众所周知的技巧是,如果一个数字的各个十进制数字的总和可以被3整除,则它可以被3整除。

示例:

2271

2+2+7+1 = 12

12 is divisible by 3, therefore so is 2271

此外,任何三个连续整数的总和必须可以被三整除。这是因为:

((n)+(n+1)+(n+2))/3 = (3n+3)/3 = n+1 = integer

因此:

如果k mod 3 == 0,那么1到k的连接可以被3整除。

如果k mod 3 == 1,那么1到k的连接不能被3整除。

如果k mod 3 == 2,则有点棘手。在这种情况下,如果kk之前的数字(评估为k的总和为{{1},则1到(k)+(k-1)的连接可被3整除。可以被三整除。

因此,最终条件是:

2k-1

然而,这可以进一步简化。

事实证明,只要(k mod 3 == 0) || ((k mod 3 == 2) && (2k-1 mod 3 == 0)) 等于k mod 32只能等于2k-1 mod 3,反之亦然。

请参阅下面的简单图表,其中显示了此行为的循环模式。

enter image description here

因此,公式可以进一步简化为:

0

或者,更简单:

(k mod 3 == 0) || (k mod 3 == 2) 

我意识到回答者已经提供了这个答案,所以我不希望这是接受的答案,只是给出一个更彻底的数学解释。

答案 3 :(得分:4)

如果数字的总和可以被3整除,则数字可以被3整除(参见here)。因此,无需“构建”您的号码,只需添加各个号码的数字即可。因此,对于你的15个案例,你不需要“构建”123456789101112131415,你只需要将[1,2,3,4,... 14,15]中的所有数字相加。

答案 4 :(得分:1)

这比听起来更简单,因为问题只需要检查非常特定格式的数字: 12345789101112131415 ... k 。您可以使用Gauss的方法快速获取数字1到k的总和,然后使用常用方法检查该总和是否可以被3整除。代码是:

'NO' if (k*(k+1)/2)%3 else 'YES'

如果你看一下k增加时出现的模式(NO,YES,YES,NO,YES,YES,......),你甚至不需要乘法或除法。简而言之,您只需要:

'YES' if (k-1)%3 else 'NO'

这是Python代码,它从文件中读取整数,如果不花太长时间也会检查答案,这样你就可以看到它是正确的。 (Python数字可以无限长,所以你不必担心溢出):

#!/usr/bin/python3
# Read integers from stdin, convert each int to a triangular number
# and output YES (or NO) if it is divisible by 3.

def sumgauss(x):
    '''Return the sum from 1 to x using Gauss's shortcut'''
    return (x*(x+1)/2)

def triangle(n):
    '''Given an integer n, return a string with all the integers 
       from 1 to n concatenated. E.g., 15 -> 123456789101112131415'''
    result=""
    for t in range(1, k+1):
        result+=str(t)
    return result

import sys
for k in sys.stdin.readlines():
    k=int(k)
    print ( 'YES' if (k-1)%3 else 'NO', end='')

    # If it wouldn't take too long, double check by trying it the hard way
    if k<100000:
        kstr=triangle(k)
        print("\t// %s modulo 3 is %d" % (kstr, int(kstr)%3))
    else:
        print('\t// 123456789101112131415...%d%d%d modulo 3 is %d' %
              tuple([k-2, k-1, k, sumgauss(k)%3]))

说到高斯的求和捷径,这个问题看起来很像家庭作业。 (高斯发明了它作为一名学生,当一位老师试图将他们的头发从头发中取出一段时间后,让他们将数字从1加到100来增加。)如果这确实是课堂作业,请确保老师知道给我 A 和stackoverflow。谢谢!

示例输出:

$ cat data
2
6
15
130000000
130000001

$ ./k3.py < data
YES // 12 modulo 3 is 0
YES // 123456 modulo 3 is 0
YES // 123456789101112131415 modulo 3 is 0
NO  // 123456789101112131415...129999998129999999130000000 modulo 3 is 1
YES // 123456789101112131415...129999999130000000130000001 modulo 3 is 0

前32个三角形数字:

$ seq 32 | ./k3.py
NO  // 1 modulo 3 is 1
YES // 12 modulo 3 is 0
YES // 123 modulo 3 is 0
NO  // 1234 modulo 3 is 1
YES // 12345 modulo 3 is 0
YES // 123456 modulo 3 is 0
NO  // 1234567 modulo 3 is 1
YES // 12345678 modulo 3 is 0
YES // 123456789 modulo 3 is 0
NO  // 12345678910 modulo 3 is 1
YES // 1234567891011 modulo 3 is 0
YES // 123456789101112 modulo 3 is 0
NO  // 12345678910111213 modulo 3 is 1
YES // 1234567891011121314 modulo 3 is 0
YES // 123456789101112131415 modulo 3 is 0
NO  // 12345678910111213141516 modulo 3 is 1
YES // 1234567891011121314151617 modulo 3 is 0
YES // 123456789101112131415161718 modulo 3 is 0
NO  // 12345678910111213141516171819 modulo 3 is 1
YES // 1234567891011121314151617181920 modulo 3 is 0
YES // 123456789101112131415161718192021 modulo 3 is 0
NO  // 12345678910111213141516171819202122 modulo 3 is 1
YES // 1234567891011121314151617181920212223 modulo 3 is 0
YES // 123456789101112131415161718192021222324 modulo 3 is 0
NO  // 12345678910111213141516171819202122232425 modulo 3 is 1
YES // 1234567891011121314151617181920212223242526 modulo 3 is 0
YES // 123456789101112131415161718192021222324252627 modulo 3 is 0
NO  // 12345678910111213141516171819202122232425262728 modulo 3 is 1
YES // 1234567891011121314151617181920212223242526272829 modulo 3 is 0
YES // 123456789101112131415161718192021222324252627282930 modulo 3 is 0
NO  // 12345678910111213141516171819202122232425262728293031 modulo 3 is 1
YES // 1234567891011121314151617181920212223242526272829303132 modulo 3 is 0 

答案 5 :(得分:0)

其实答案很简单,如果能被3整除的数字之和也能被3整除。

字符串 ans=(((1 + num) * num) / 2) % 3 == 0 ? "是" : "否";

根据问题数字之和可以认为是1到n的数字之和,sum=(n*(n+1))/2 *确保将整个事物除以 2

另一种方法: 字符串 ans=n % 3 !=1 ? "是" : "否";

答案 6 :(得分:-1)

你可以证明,如果n或n-2可以被3整除,那么n的总和可以被3整除(例如,在你的情况下,sum(1 ... 8),sum(1..9) ,总和(1..11)等。)。