Project Euler 399
Project Euler 399
题目
Squarefree Fibonacci Numbers
The first \(15\) fibonacci numbers are:
\(1,1,2,3,5,8,13,21,34,55,89,144,233,377,610.\)
It can be seen that \(8\) and \(144\) are not squarefree: \(8\) is divisible by \(4\) and \(144\) is divisible by \(4\) and by \(9\).
So the first \(13\) squarefree fibonacci numbers are:
\(1,1,2,3,5,13,21,34,55,89,233,377\) and \(610.\)
The \(200\text{th}\) squarefree fibonacci number is:
\(971183874599339129547649988289594072811608739584170445.\)
The last sixteen digits of this number are: \(1608739584170445\) and in scientific notation this number can be written as \(9.7e53\).
Find the \(100 000 000\text{th}\) squarefree fibonacci number.
Give as your answer its last sixteen digits followed by a comma followed by the number in scientific notation (rounded to one digit after the decimal point).
For the \(200\text{th}\) squarefree number the answer would have been: \(1608739584170445,9.7e53\)
Note:
For this problem, assume that for every prime \(p\), the first fibonacci number divisible by \(p\) is not divisible by \(p^2\) (this is part of Wall’s conjecture). This has been verified for primes \(\le 3\cdot 10^{15}\), but has not been proven in general.
If it happens that the conjecture is false, then the accepted answer to this problem isn’t guaranteed to be the \(100 000 000\text{th}\) squarefree fibonacci number, rather it represents only a lower bound for that number.
解决方案
令\(N=10^8\)。我们给题目额外假设(Wall 猜想相关):对任意素数 \(p\),第一次出现 \(p\mid F_{a_p}\) 时不会发生 \(p^2\mid F_{a_p}\)(也就是 \(v_p(F_{a_p})=1\))。
论文里定义了 rank of apparition:\(\kappa(n)=\min\{m\ge 1:n\mid F_m\}.\)并在引理1给出关键性质:对任意正整数 \(m,n\),有\(n\mid F_m \iff \kappa(n)\mid m.\)
因此,对素数 \(p\):
- 令 \(a_p = \kappa(p)\)(最小使得 \(p\mid F_{a_p}\) 的下标)。
- 那么 \(p\mid F_n\) 当且仅当 \(a_p\mid n\)。
论文的引理4给出:设 \(p^l\) 是 \(F_{\kappa(p)}\) 中 \(p\) 的最高幂(即 \(p^l\mid F_{\kappa(p)}\) 且 \(p^{l+1}\nmid F_{\kappa(p)}\)),则\(\kappa(p^{l+1})=p\kappa(p).\)
由于 \(\kappa(p)\) 的定义保证 \(p\mid F_{\kappa(p)}\),因此 \(F_{\kappa(p)}\) 中 \(p\) 的指数至少为 \(1\)。而题目给定的 Wall 假设进一步要求 \(p^2\nmid F_{\kappa(p)}\),这就意味着该指数不可能达到 \(2\)。因此,引理4中的\(l\)只能是\(1\)。
把 \(l=1\) 代入引理4,得到关键结论:\(\kappa(p^2)=p\kappa(p)=pa_p.\)
由引理 1 对 \(n=p^2\) 的情形,得到\(p^2\mid F_n \iff \kappa(p^2)\mid n.\)再代入上一步得到的 \(\kappa(p^2)=pa_p\),可化为 \(p^2\mid F_n \iff (pa_p)\mid n.\)
因此,\(F_n\) 不是 squarefree 当且仅当存在某个素数 \(p\) 使得 \(p^2\mid F_n\),等价于存在 \(p\) 使得\((pa_p)\mid n.\)换句话说,令\(b_p=pa_p,\)则 squarefree 的下标 \(n\) 恰好是所有不被任何 \(b_p\) 整除的正整数。
于是原问题等价为:在 \(n=1,2,3,\dots\) 中筛去所有满足 \(b_p\mid n\) 的下标,剩下的下标按从小到大第 \(N\) 个记为 \(n^{\ast}\),答案即为 \(F_{n^{\ast}}\)
直接模拟斐波那契模 \(p\) 直到出现 \(0\) 虽然可行,但总体步数很大。更快的做法是利用论文证明定理1到定理2时引用的经典结论:对任意素数 \(p\ne 5\),有 \(p\mid F_{p-\left(\frac{p}{5}\right)}.\)其中\(\left(\dfrac{a}{b}\right)\)是指勒让德符号。
因此 \(a_p=\kappa(p)\)(最小使得 \(p\mid F_{a_p}\) 的下标)一定整除
\[ B= \begin{cases} p-1,&\text{if}\quad \left(\frac{p}{5}\right)=1\quad(p\equiv \pm 1\pmod 5),\\ p+1,&\text{if}\quad \left(\frac{p}{5}\right)=-1\quad(p\equiv \pm 2\pmod 5). \end{cases} \]
于是可以用按素因子缩小阶的方法求最小 \(a_p\):
- 先令 \(k=B\)(由上面的结论可知 \(p\mid F_k\),因此 \(a_p\mid k\))。
- 分解 \(k\)。对每个素因子 \(q\),尝试把 \(k\) 除以 \(q\):若 \(p\mid F_{k/q}\) 仍成立,就令 \(k\leftarrow k/q\) 并继续;否则停止对这个 \(q\) 的缩小。
- 最终的 \(k\) 就是 \(a_p\)(因为经过逐个素因子的“能除就除”,\(k\) 已经被削到仍满足 \(p\mid F_k\) 的最小可能值)。
判断 \(p\mid F_t\) 用斐波那契快速倍增法在 \(O(\log t)\) 时间算出 \(F_t\bmod p\) 即可。
注意,斐波那契快速倍增是通过把下标从 \(k\) 一次性翻到 \(2k\) 或 \(2k+1\),用 \(O(\log n)\) 步就能算出 \(F_n\)(常同时得到 \(F_{n+1}\))。基于下面两条倍增恒等式:设 \(F_0=0,F_1=1\),对任意 \(k\ge 0\),\(F_{2k}=F_k(2F_{k+1}-F_k),F_{2k+1}=F_{k+1}^2+F_k^2.\)因此用 \(O(\log n)\) 步就能算出 \(F_n\)。
因此,有了所有 \(b_p=p\cdot a_p\)(且只需保留 \(b_p\) 不超过上界 \(L\) 的那些),就可以像筛合数一样筛下标:
- 对每个 \(b\),把 \(b,2b,3b,\dots\) 这些下标标记为“坏”(对应 \(F_n\) 含某个 \(p^2\) 因子)。
- 未被标记的下标就是 squarefree Fibonacci 的下标。
因此,实际目标下标在 \(1.31 N\) 左右,取 \(L=2N\) 足够覆盖;最终找到第 \(N\) 个未被标记的下标 \(n^{\ast}\)。
对于\(F_{n^{\ast}}\)的低16位,直接使用斐波那契快速倍增计算\(F_{n^{\ast}}\bmod M\)即可,其中\(M=10^{16}\)。
对于\(F_{n^{\ast}}\)的科学计数法,用 Binet 近似的对数形式即可:
\[ \log_{10}F_n \approx n\log_{10}\varphi-\log_{10}\sqrt 5, \varphi=\frac{1+\sqrt5}{2}. \]
令 \(x=\log_{10}(F_n)\),则指数 \(e=\lfloor x\rfloor\),尾数 \(m=10^{x-e}\)(\(1\le m < 10\))。
代码
1 | import math |