Day 166-Q5 — 2026-09-30 | Pisano 周期(フィボナッチ数列の mod m での周期)

2026-09-30 赤色 Master (Phase 8+) ★★★★★★★★★ 9/30 のバックフィル分 数論(焦点帯 M3)。素数冪ごとの周期を素数の周期から作り、π(p) は p−1 または 2(p+1) の約数であることを使って、10^12 までを素因数分解と倍加法で求める。π(p^e)=π(p) と置く誤りを数で確かめる

問題

フィボナッチ数列 $F_0=0,\ F_1=1,\ F_{n+2}=F_{n+1}+F_n$ を $m$ で割った余りの数列 $F_0\bmod m,\ F_1\bmod m,\dots$ は周期的になる。最小の正の周期 $\pi(m)$($F_{\pi}\equiv0,\ F_{\pi+1}\equiv1\pmod m$ となる最小の正整数 $\pi$)を求めよ。

入力形式

m

制約

#条件
1$1\le m\le10^{12}$($m=1$ のとき $\pi(1)=1$)

入出力例

入力例1

10

出力例1

60

入力例2

1

出力例2

1

入力例3

1000000007

出力例3

2000000016

($10^9+7$ は素数で $\equiv\pm2\pmod5$ なので $\pi$ は $2(p+1)$ の約数。$2(p+1)=2000000016$ そのもの)

入力例4

1000000000000

出力例4

1500000000000

($\pi(10^k)=15\cdot10^{k-1}$ の形)

背景と出典

$\pi(p)$ について「$p\equiv\pm1\pmod5$ なら $p-1$ の約数、$p\equiv\pm2\pmod5$ なら $2(p+1)$ の約数、$\pi(2)=3,\ \pi(5)=20$」は標準的な結果と記憶している(本セッションでは原典を確認していない。Wall 1960 の論文が出典と記憶)。$\pi(p^e)=p^{e-1}\pi(p)$ は Wall–Sun–Sun 素数が存在しない限り成り立つ、とも記憶している。そのような素数は今まで見つかっていないと記憶しているが、探索範囲を含め本セッションでは確認していない。本問の制約($m\le10^{12}$)で確認した範囲は、下の検証ログのとおり。

この問題で確かめたいのは次の 3 点。(1) 素数冪と合成数を含む $m\le3000$ の全てで、反復の周期と一致すること。(2) $\pi(p^e)=\pi(p)$ と置く誤りが、いくつの $m$ で外れるか。(3) $m\approx10^{12}$ で、求めた値が本当に最小の周期になっていること($F_\pi\equiv0,F_{\pi+1}\equiv1$ かつ、$\pi$ を素因数で割ると成り立たない)。

ヒント(クリックで段階的に開示)

ヒント1(方向性)

$m=\prod p_i^{e_i}$ のとき、$\pi(m)=\mathrm{lcm}_i\ \pi(p_i^{e_i})$(各素数冪で周期になる最小の $n$ の最小公倍数)。まず素数 $p$ の $\pi(p)$ を考える。直接シミュレートすると $\pi(p)$ は最大 $2(p+1)$ 程度で、$p=10^{12}$ では間に合わない。

ヒント2(アプローチ)

$\pi(p)$ は、$p\equiv\pm1\pmod5$ なら $p-1$ の約数、そうでなければ $2(p+1)$ の約数($p=2,5$ は別扱い)。その数 $T$ から出発し、$T$ の素因数 $q$ ごとに「$T/q$ でも周期になるなら $T$ を $T/q$ に置き換える」を繰り返せば最小になる。周期になるかは $(F_T,F_{T+1})\equiv(0,1)$ で判定し、フィボナッチ数は倍加法で $O(\log T)$。

ヒント3(誘導)

素数冪は $\pi(p^e)=p^{e-1}\pi(p)$(Wall–Sun–Sun 素数でない限り)。$m\le10^{12}$ の素因数分解は $\sqrt m\le10^6$ までの試し割りで済む。$T$ は最大で約 $2\times10^{12}$ なので、$T$ の素因数分解には $\sqrt T\approx1.42\times10^6$ までの素数が要る(篩の上限を $1.5\times10^6$ にした理由)。

模範解答 (Python)

模範解答を表示する(まず自力で解いてから)
import sys
from math import gcd
def fibpair(k, m):
    # (F_k, F_{k+1}) mod m を倍加法で
    a, b = 0, 1
    for bit in bin(k)[2:]:
        c = a * ((2*b - a) % m) % m
        d = (a*a + b*b) % m
        if bit == '1': a, b = d, (c + d) % m
        else: a, b = c, d
    return a, b
def factor(x, primes):
    f = {}
    for p in primes:
        if p*p > x: break
        while x % p == 0:
            f[p] = f.get(p, 0) + 1; x //= p
    if x > 1: f[x] = f.get(x, 0) + 1
    return f
def pisano_prime(p, primes):
    if p == 2: return 3
    if p == 5: return 20
    T = p-1 if p % 5 in (1, 4) else 2*(p+1)       # π(p) は T の約数
    for q in factor(T, primes):
        while T % q == 0 and fibpair(T//q, p) == (0, 1 % p):
            T //= q
    return T
def main():
    m = int(sys.stdin.readline())
    LIM = 1500000
    sv = bytearray([1])*(LIM+1); sv[0] = sv[1] = 0
    for i in range(2, int(LIM**0.5)+1):
        if sv[i]: sv[i*i::i] = bytearray(len(sv[i*i::i]))
    primes = [i for i in range(LIM+1) if sv[i]]
    res = 1
    for p, e in factor(m, primes).items():
        pi = pisano_prime(p, primes) * p**(e-1)   # π(p^e)=p^(e-1)π(p)(Wall–Sun–Sun 素数が無い前提)
        res = res // gcd(res, pi) * pi
    print(res)
main()

計算量: 篩 $O(L\log\log L)$($L=1.5\times10^6$)、各素因数について $T$ の素因数分解 $O(\pi(L))$ と倍加法 $O(\log T)$ を素因数の個数回。実測(Python 3.14、M1 Mac)で $m=10^{12}$ が 0.09 s(プロセス全体)。

Step-by-Step 解説

1周期は素数冪の最小公倍数

$m$ を割る互いに素な部分ごとに周期を求めて最小公倍数を取る(中国剰余定理)。$\pi(1)=1$。

2素数 $p$ の周期の候補

$p\ne2,5$ のとき、$p\equiv\pm1\pmod5$ なら $\pi(p)\mid p-1$、そうでなければ $\pi(p)\mid2(p+1)$。$p=2$ は $0,1,1,0,1,1$ で 3、$p=5$ は 20。

3素因数で割って最小にする

候補 $T$ から出発し、$T$ の各素因数 $q$ について「$(F_{T/q},F_{T/q+1})\equiv(0,1)$ ならば $T\leftarrow T/q$」を、割れなくなるまで繰り返す。$T$ が周期なら $T$ の約数のうち周期になる最小のものが $\pi$ なので、素因数ごとに割れるだけ割れば最小になる。

4倍加法でフィボナッチを求める

$F_{2k}=F_k(2F_{k+1}-F_k)$、$F_{2k+1}=F_k^2+F_{k+1}^2$ を mod $p$ で使い、$(F_k,F_{k+1})$ を上位ビットから作る。$\log_2T\le41$ 回の繰り返し。

5素数冪に持ち上げる

$\pi(p^e)=p^{e-1}\pi(p)$ とする。$m\le3000$ の全てで反復の周期と一致した。これはこの範囲に反例が無いことしか示さず、一般の保証にはならない。置き換えず $\pi(p^e)=\pi(p)$ とすると、$m\le3000$ のうち 546 個で外れた。

迷った他案と採らなかった理由

案計算量採否理由
素数ごとの $T$ から約数を落とす+倍加法+素数冪の持ち上げ(本解)$O(\sqrt m)$ の試し割り+素因数ごとに $O(\log m)$採用$m\le3000$ の全件、$3001\ldots60000$ の 200 件で反復と一致
$F_n\bmod m$ をそのまま反復$O(\pi(m))$、最大 $6m$検算用のみ$m\le6\times10^4$ でしか動かない
行列 $\begin{pmatrix}1&1\\1&0\end{pmatrix}$ の位数を探索$O(\pi(m)\log)$不採用反復と同じ規模。周期の約数構造を使わない
$\pi(p^e)=\pi(p)$ のまま$O(\sqrt m)$不採用$m\le3000$ で 546 個外れる

前提が変わったら:

  • $m>10^{12}$(例えば $10^{18}$)では $\sqrt m=10^9$ の試し割りが重く、Pollard の rho 法などの素因数分解が要る。本問の制約を $10^{12}$ にした理由。実装していない
  • Wall–Sun–Sun 素数が見つかると、その素数 $p$ で $\pi(p^2)=\pi(p)$ になり、本解の持ち上げが外れる。そのような素数は見つかっていない、と記憶している(未確認)
  • 一般のフィボナッチ型数列($a_{n+2}=ba_{n+1}+ca_n$)や別の初項では、周期の候補の形($p\pm1$ の約数)が変わる。本解はそのままは使えない

よくあるミス

ミス原因正しい書き方
$\pi(p^e)=\pi(p)$ と置く素数冪の周期は素数の周期の $p^{e-1}$ 倍になることを忘れるpi * p**(e-1)
$p=5$ を $p-1$ か $2(p+1)$ の約数として扱う$5\equiv0\pmod5$ はどちらの場合でもない20 を直接返す
$p=2$ の周期を 3 でなく 2 などにする$0,1,1,0,1,1$ を確かめていない3 を直接返す
篩の上限が $\sqrt T$ に届かない$T\le2\times10^{12}$ で $\sqrt T\approx1.42\times10^6$上限を $1.5\times10^6$ にして、最後の残りを素数と見なす

次のステップ

  • 発展1: $\pi(m)$ が $m$ の候補($m\le10^{12}$)のうち最大になる $m$ を探し、$6m$ との比を見る
  • 発展2: $m>10^{12}$ に拡張するために Pollard の rho 法を足す
  • 次回予告: 焦点帯 M1 から 3 問以上を含む通常のローテーション

検証ログ(本セッションで実行した数値)

  • 反復との照合(実測): $1\le m\le3000$ の全 3000 件で、$(F_n,F_{n+1})\equiv(0,1)$ になる最小の $n$ を反復で求めた値と一致。$3001\le m\le60000$ のランダム 200 件も一致。素数冪($2,3,5,7,11,13,101,997$ の $e\le4$、$m\le3\times10^5$)も一致
  • 誤った式(実測): $\pi(p^e)=\pi(p)$ と置くと、$m\le3000$ の 546 個で外れる
  • 最小性の確認(実測): $5\times10^{11}\le p\le10^{12}$ の素数 60 個と、$10^{11}\le m\le10^{12}$ の 100 個について、求めた $\pi$ が $(F_\pi,F_{\pi+1})\equiv(0,1)$ を満たし、$\pi$ を素因数で割ると満たさないことを確認。ただし最小性の判定に使う素因数分解は本解と同じ関数なので、分解が不完全でも検出できない(篩の上限が $\sqrt T$ 以上であることは別途確認)
  • 入力例(実測): 10 は 60、1 は 1、1000000007 は 2000000016、$10^{12}$ は 1500000000000(出力例どおり)
  • 実行時間(実測): $m=10^{12}$ で 0.09 s(プロセス全体)
  • 扱っていない範囲: Wall の定理と $\pi(p^e)=p^{e-1}\pi(p)$ の原典確認、Wall–Sun–Sun 素数の探索範囲の確認、$m>10^{12}$、一般の線形漸化式

自己評価

自分の回答

気づき・メモ