F - 998244353 → 1000000007 Editorial by snuke

ゴルフ(17行)

18行解法です。挑戦者求む。
追記:17行になりました。一番下に解説書きました。

18
mul C A B
rem X C
mul X X 4915446
rem X X
mul X X 1000000007
add X C X
mul C X 8456992263029997534
rem X C
mul X X 4915446
rem X X
mul X X 1000000007
add X C X
mul C X 996491785301655553
add X C 17479186996
mul X X 998244353
rem X X
mul X X 5046007969279823707
add C C X

まずは公式解説を読んで来て下さい。

montgomery reductionを \(MR\)、その if (t >= N) t -= N; がないバージョンを \(iMR\) とします。
答えは \(MR(iMR(A*B)*R_2)\) として求められます。

3-8行目と9-14行目が \(iMR\) です。(8行目は \(C=C*996491785301655553\)\(A=C*320946142(=R_2)\) をマージしたものです)
コード中のマジックナンバーは \(N' = 4915446, R^{-1}\ mod\ 2^{64} = R^{2^{63}-1}\ mod\ 2^{64} = 996491785301655553\) です。

15-19行目が if (t >= N) t -= N; です。
\(0 \le t \lt 2N\) を前提にしています。
方針としては、

  1. \(X = \lfloor 2^{64} / R \rfloor + 1\) とし、\(B = t+(X-N)\) とする。
    • \(t \ge N\) のときにちょうど \(B*R\) がオーバーフローする
  2. \(B = (B*R\ mod\ 2^{64})\ mod\ R\) を求める。\(Y = -2^{64}\ mod\ R\) とすると、
    • \(t \lt N\) のとき \(0\)
    • \(t \ge N\) のとき \(Y\)
  3. \(t = t+(B / Y)*-N\) で答えが求まる。
    • \(Y=66192443\) は奇数なので \(mod\ 2^{64}\) で逆元が存在する
    • \(B/Y\)\(mod\ R\) で求める手もありますね

マジックナンバーは \(X-N = 17479186996, Y^{-1}\ mod\ 2^{64} = 5046007969279823707\) です。


正当性について

そもそも、本来のmontgomery reductionでは \(N<R, T < NR\) が前提条件となっているため、この問題では \(MR(T) \ge N\) となってしまう場合があります。
そのため、正当性を保証するためには各段階で取る値の範囲を丁寧に解析していく必要があります。

\(iMR(iMR(A*B)*R_2) \lt 2N\) を確認したいです。

  • \(A*B \lt N^2\)
  • \(iMR(A*B) \lt (N^2+NR)/R \lt 2.1N\)
  • \(iMR(A*B)*R_2 \lt 2.1N*0.33R \lt NR\)
  • \(iMR(iMR(A*B)*R_2) \lt (NR+N(R-1))/R \lt 2N\)

コードゴルフについて

\(iMR(iMR(iMR(A*B)*R_3))\) で答えを求めると、コードを再利用しやすいため、こちらの方がコードゴルフには向いています。
\(R_3 = R^3\ mod\ N\) とします)

ただ、正当性を示すのが先程より難しいです。

  • \(iMR(A*B)*R_3 \lt 2.1N*0.63R \lt 1.4NR\)
  • \(T = iMR(iMR(A*B)*R_3)\) とする
  • \(T \lt (1.4NR+N(R-1))/R \lt 2.4N\)
  • \(TN'\ mod\ R \le R-3\) の場合:
    • \(iMR(T) \lt (2.4N+N(R-3))/R \lt N\) なのでok
  • \(TN'\ mod\ R = R-1,R-2\) の場合:
    • \(T = N-R, N, N+R, 2N-2R, 2N-R, 2N\) のいずれか
    • それぞれ、\(iMR(T) = N-1, N, N+1, N-2, N-1, N\)
    • \(iMR(T)=N, N+1\) のケースのみを確認すれば良い
      • \(iMR(T)=N\) の場合:
        • 答えが \(0\) になるのは \(A=B=0\) のみで、これは正しく動く
      • \(iMR(T)=N+1\) の場合:
        • \(T=N+R\)
        • \(iMR(A*B)*R_3 = TR-N(R-i) = R^2+Ni\)
        • \(R^2+Ni\ mod\ R_3 = 0\) となる最小の \(i\)\(359331038\)
        • このとき \((R^2+Ni)/R_3 = 2004924105\)
        • \(iMR(A*B) = AB-N(R-j)\) の最小値は \(2004924105-N(R-1) = 1003159807022118601\)
        • \(\sqrt{1003159807022118601} \gt 1001578657 \gt N\) なので、制約の範囲では落ちるケースはない
        • \(A, B = 1115529708, 899267676\) あたりが小さそう)

17行解法について

mizarjpさんの解法を参考にしました。

ifパートの \(0\) または \(Y\) を求める部分(上のコードの15~17行目)を 1 行減らせます。

17
mul C A B
rem X C
mul X X 4915446
rem X X
mul X X 1000000007
add X C X
mul C X 8456992263029997534
rem X C
mul X X 4915446
rem X X
mul X X 1000000007
add X C X
mul C X 996491785301655553
add X X 17448499713788033588
rem X X
mul X X 5046007969279823707
add C C X

15,16行目が変更箇所。
15行目の時点で \(X\) には \(tR\)\(R\) で割る前の値)が入っています。

  • \(((tR-NR)\ mod\ 2^{64})\ mod\ R\) を求める
    • \(t \lt N\) のとき \(2^{64}\ mod\ R\)
    • \(t \ge N\) のとき \(0\)

負の方向のオーバーフローを使う方針。
この方針には欠点があり、 \(2^{64}\ mod\ R = 932051910\) が偶数であるため \(mod\ 2^{64}\) での逆元が存在せず、2行のロスが発生します。
そこで、remの前に \(Y = -2^{64}\ mod\ R\) を足してみると、

  • \(((tR-NR+Y)\ mod\ 2^{64})\ mod\ R\) を求める
    • \(t \lt N\) のとき \(0\)
    • \(t \ge N\) のとき \(Y\)

となり、\(Y\) は奇数なので逆元があって嬉しい。
\(Y \lt R\) なのでオーバーフローの境界が変わらない点もポイント。

マジックナンバー:\(-NR+Y = 17448499713788033588\)

追記:\(R\) で割る前の値を使えば18行解法の16行目を消す事ができる、という見方もできる。この場合マジックナンバーは \((X-N)*R\) になるが、こちらも \(17448499713788033588\) となり一致する。\(XR\ mod\ 2^{64}=Y\) なので確かにそうなる。

posted:
last update: