在逛segmentfault
论坛时,看到了这样一个提问,于是花了点时间详细的解答了,顺便记录在本文中。
原题链接https://segmentfault.com/q/1010000008553427/a-1020000008559091
遇到这个问题时,第一个想法就是先用代码进行暴力破解,然后又发现整数整除问题可以用费马小定理进行分析,于是就有了以下回答题纲:
function getMinDividedNum(n) {
var sum = 1,
len = 1;
while (sum % n) {
len++;
sum = (sum % n) * 10 + 1;
}
return len;
}
// 测试用例
// 注意,并不是所有数字都能输入,只能是素数或者由素数乘积组成的数
// 这里就相当于直接人为的约定了输入前提了
var num = 2013;
console.log('n:' + num + ',len:' + getMinDividedNum(num));
// 输出:n:2013,len:60
以上代码的核心其实就是判断1,11,111
等N位数能否被n整除,也就是sum=sum*10+1
。
但是考虑到最大值边界问题,于是将上述公式换为了
sum= (sum % n)*10+1
之所以能这样转换,是因为: (举例)
111
是否能被3整除(1*10+1)*10+1
2+1
能否被3整除即可首先得知道的是,费马小定理是欧拉定理的一种特殊情况,欧拉定理描述的是关于同余的性质,而费马定理如下:
假如a是整数,p是质数,且a,p互质(两者只有一个公约数1),那么a的(p-1)次方除以p的余数恒等于1
即a^(p-1)%p=1
关键来了,本题与费马小定理有什么关系呢?
本题中,2013=3*11*61
,所以能被2013整除,就需要满足
而前两者很容易就根据下面的条件判断出:
因此马上就可以将条件转换为:
接下来就剩下了一个问题: n个1能被61整除,需要满足什么?接下来费马小定理就派得上用处了。
我们可以得知: 61和10互素。
所以套用上述的公式,可以得出: 10^(60)%61=1
,即10^(60)=1 (mod 61)
所以:10^(60)-1=0 (mod 61)
而10^60 -1
就是60个9组成的数
,也就是说 60个9组成的数能够被61整除。
那么自然60个1组成的数能够被61整除(因为61与3无关)。
同时60又是6的倍数,因此60个n组成的数能够被2013整除。
继续判断,费马小定理并不保证(p-1)是最小的指数,但是一定是最小指数的倍数。
所以继续判断60的约数,60的符合条件的约数(6的倍数)有,6,12,30,60。
依次计算6,12,30
这三个数,发现都不满足条件,于是得出只有60满足条件。
因此得出了结论: n至少为60时,n个1组成的数能够被2013整除
https://dailc.github.io/2017/03/04/fermatsLittleTheoremN1.html