リュカ数を求めるには、愚直再帰やメモ化再帰、受けとるDPや末尾再帰などがありますが、いずれも指数時間で効率が良くないので、他の方法を考えることにします。
また、リュカ数には一般項がありますが、これは計算過程に無理数を含み、余りを求めるのは困難です。
そこで、行列の累乗で計算することにします。
リュカ数の漸化式を行列の積で表すと画像の一番上の式のようになります。
つまり、N番目のリュカ数は画像の一番下の式のように表せます。
行列の累乗を効率的に計算することが出来れば、答えも効率的に求まりそうです。
行列なので、pow関数を使うことは出来ませんが、繰り返し二乗法と呼ばれる方法を使うことで、線形時間で累乗を計算できます。
任意の整数は二進数で表すことが出来ます。
整数mが二進数でabcdと表現出来るとき、
n^m=n^(a000+b00+c0+d)=n^a000*n^b00*n^c0*n^d
となります。
n^(1<<k)は、二乗をk回繰り返すことで線形時間で求まるので、累乗は線形時間で求まることになります。(以下N^Mを求めるプログラム)
A=1
WHILE M
IF M AND 1 THEN A=A*N
N=N*N
M=M>>>1
WEND