Project Euler 358

Project Euler 358

题目

Cyclic numbers

A cyclic number with \(n\) digits has a very interesting property:

When it is multiplied by \(1, 2, 3, 4, \dots n\), all the products have exactly the same digits, in the same order, but rotated in a circular fashion!

The smallest cyclic number is the \(6\)-digit number \(142857\) :

\(\begin{aligned} 142857 \times 1 = 142857\\ 142857 \times 2 = 285714\\ 142857 \times 3 = 428571\\ 142857 \times 4 = 571428\\ 142857 \times 5 = 714285\\ 142857 \times 6 = 857142 \end{aligned}\)

The next cyclic number is \(0588235294117647\) with \(16\) digits :

\(\begin{aligned} &0588235294117647 \times 1 = 0588235294117647\\ &0588235294117647 \times 2 = 1176470588235294\\ &0588235294117647 \times 3 = 1764705882352941\\ &\dots\\ &0588235294117647 \times 16 = 9411764705882352\\ \end{aligned}\)

Note that for cyclic numbers, leading zeros are important.

There is only one cyclic number for which, the eleven leftmost digits are \(00000000137\) and the five rightmost digits are \(56789\) (i.e., it has the form \(00000000137\dots56789\) with an unknown number of digits in the middle). Find the sum of all its digits.

解决方案

本解决方案参考了循环数页面的部分内容。

循环数和以质数为分母的分数单位\(\dfrac{1}{p}\)息息相关。在\(b\)进制下,如果分数\(\dfrac{1}{p}\)以小数形式的循环节长度为\(p-1\),那么\(\dfrac{1}{p}\)的前\(p-1\)位小数组合起来就是一个\(b\)进制下的循环数。

此外还提到,如果\(\dfrac{1}{p}\)\(b\)进制下的循环节长度为\(p-1\),那么\(b\)是群\(\mathbb{Z}_p^{\star}\)原根

最终,通过一个质数\(p\)和一个满足条件的进制数\(b\),可以构造出一个循环数\(c(b,p)=\dfrac{b^{p-1}-1}{p}\).假设进制\(b\)\(10\),那么\(f(b,p)\cdot p\)恰好为\(b^{p-1}-1\),数位和为\(9(p-1)\)。分拆\(f(b,p)\cdot p=f(b,p)+f(b,p)\cdot(p-1)\),注意到这两个数\(f(b,p)\)实际上是\(f(b,p)\cdot(p-1)\)的数位逆序,因此这两个数相等,最终循环数\(f(b,p)\)的数位和是\(\dfrac{(b-1)(p-1)}{2}\).

由于这个数的开头是\(00000000137\),那么所需要寻找的质数\(p\)满足\(0.00000000137\le\dfrac{1}{p}<0.00000000138\).在这个范围内进行寻找。

为了加速程序运行,质数判断和原根判断是最慢的两个过程,应该放在后面判断。我们假设目前枚举出来的数\(p\)是个质数,那么根据\(f(n,p)\cdot p=b^{p-1}-1\),判断\(p\)是否满足\(56789\cdot p\%10^5=10^5-1\),如果是那么再进行剩下两个过程的判断。另外一方面,通过第一个判断的概率非常小,这足以让程序能够快速运行。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from math import floor, ceil
from sympy import is_primitive_root
from tools import phi, is_prime

left = "00000000137"
right = "56789"
val = float("0." + left)
ed = floor(1 / val)
val += 10 ** -len(left)
st = ceil(1 / val)
right_v = int(right)
mod = 10 ** len(right)
mod_1 = mod - 1
ph = phi(mod)
p = st - 1

for p in range(st | 1, ed + 1, 2):
if right_v * p % mod == mod_1 and is_prime(p) and is_primitive_root(10, p):
ans = (p - 1) // 2 * 9
break
print(ans)

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
Ujimatsu Chiya 微信 微信
Ujimatsu Chiya 支付宝 支付宝