我正在努力解决时间限制非常低(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"
答案 0 :(得分:10)
看看:
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 = 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
,则有点棘手。在这种情况下,如果k
和k
之前的数字(评估为k
的总和为{{1},则1到(k)+(k-1)
的连接可被3整除。可以被三整除。
因此,最终条件是:
2k-1
然而,这可以进一步简化。
事实证明,只要(k mod 3 == 0) || ((k mod 3 == 2) && (2k-1 mod 3 == 0))
等于k mod 3
,2
只能等于2k-1 mod 3
,反之亦然。
请参阅下面的简单图表,其中显示了此行为的循环模式。
因此,公式可以进一步简化为:
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)等。)。