phyllo’s algorithm note

レッドコーダーへの道のりは遠い。休んでる場合じゃない!

ABC161 F. Division or Substraction

問題

正の整数Nが与えられる。

2以上N以下の整数Kを決めて、NがK未満になるまで次の操作を繰り返す

  • NがKで割り切れるならNをN/Kに置き換える。そうでないなら、NをN-Kに置き換える

最終的にNが1になるようなKはいくつあるか?

制約

  • 2 <= N <= 10^12

解法

まず、「NがKで割り切れる」というのは、Nを割れる数=Nの約数である。まず、これが割る場合のKの候補となる。
Nの約数dでNを割ったあと、それがまだdで割れるなら操作の条件から割り続ける必要がある。
なので、Nをdで割り切れるだけ割った後の値N'が最終的に1になるかを考えれば良い。

上記以外で、引き算をしてから割り算が発生するか?考える。
引き算してから割り算が発生する=「X-KをしてからKの倍数になるか?」ということだが、これはXがKの倍数のときしかありえない(上の事例)ので、引き算をしてから割り算が発生することはない。
したがって、Nの約数以外は、引き算のみが行われると考えて良い。

最後に、あるKがあって、あるXが引き算操作のみで最終的に1になるか?を考える。
これは「X-Kを繰り返して最終的に1になるか?」であるが、引き算操作だけ考えればよいので、
1 -> 1+K -> 1+2K -> 1+3K -> 1+4K -> ...
となるKのみである。

言い換えると、
X = 1 + mK (m>0の整数)
の場合に最終的に1になるので、XはKで割ってあまりが1の場合=「X mod K=1」であればよい。

割り算が発生するケースは、Nの約数について、割れるだけ割ったあとの値XがX mod K = 1を見れば良い。
割り算が発生しないケースは、X=Nの場合=「N = 1 + mK」になる場合なので、K=(N-1)の約数が答えになる。

約数列挙と割れるだけ割る操作の部分の計算量がかかるが、約数列挙はO(sqrt(N))程度、割り切れるだけ割る操作は、約数の個数*O(logN)程度なので、十分高速に求められる。