Q、47バイト
m:{*/1_-':|(0<){y-x x bin y}[*+60(|+\)\1 0]\x}
テスト
+(i;m'i:1 2 3 4 5 6 7 8 9 42 1000 12345)
ペア(i、map(m、i))として読み取ります。ここで、mは計算関数、iは異なる引数です。
書く
1 1
2 2
3 3
4 3
5 5
6 5
7 10
8 8
9 8
42 272
1000 12831
12345 138481852236
説明
n funtion\arg
関数(関数(関数(...関数(引数)))をn回(内部TAL再帰を使用して)適用し、結果のシーケンスを返す。我々はfibonnaci一連の60の最初の項目を計算する*+60(|+\)\1 0
。その場合、関数は、(あります| +):+ \シーケンスに適用すると、部分和(ex + \ 1 2 3は1 3 6)が計算され、|はseqを逆にします。合計が逆になり60(|+\)\1 0
、シーケンス1 0、1 1、2 1、3 2、5 3、8 5、13 8、21 13、...が生成されます*+
reverse。シーケンス1 0、1 1、2 1、3 2、5 3、8 5、13 8、21し、この結果に適用して、反転(対置)し、最初に取得します。 1 2 3 5 8 13 21 34 55 ..
(cond)function\args
cond trueの間にfunction(function(.. function(args))))を適用し、部分的な結果のシーケンスを返します
function[arg]
複数の引数の関数に適用すると、投影が作成されます(部分的なアプリケーション)
引数に名前を付けることはできますが、暗黙的な名前はx、y、zです
{y-x x bin y}[*+60(|+\)\1 0]
部分投影を使用してargs x、yでラムダを宣言します(arg xはフィボナッチ数列で、* + 60(| +)\ 1 0として計算されます)。xはフィボナッチ値を表し、yは処理する数を表します。より大きいフィボナッチ数<= y(x bin y
)のインデックスを見つけ、xの対応する値を減算するには、バイナリ検索(bin)が使用されます。
部分的な結果から製品を計算するには、それらを逆にして各ペアの差を計算し(-':|
)、最初の(1_
0であるため)をドロップし、乗算します(*/
)。
累積和に関心がある場合、コードは同じですが、+/
ではなくになり*/
ます。また、+または*の代わりに他のダイアディック演算子を使用することもできます
実行効率について
このコンテストでは効率が問題にならないことを知っています。しかし、この問題では、線形コストから指数コストまで幅があるため、私はそれについて興味があります。
2つ目のバージョン(コメントを除く長さ48バイト)を開発し、両方のバージョンでテストケースを1000回繰り返しました。
f:*+60(|+\)\1 0;m:{*/1_-':|(0<){x-f f bin x}\x} /new version
実行時間:オリジナルバージョン0'212 seg、新しいバージョン0'037 seg
元のバージョンでは、関数アプリケーションごとにfibbonaciシリーズを計算します。新しいバージョンでは、フィボナッチを1つだけ計算します。
どちらの場合でも、フィボナッチ数列の計算は末尾再帰を使用します
2
、として分解できます-1 + 3
。ツェッケンドルフの定理の正しい説明は、正のフィボナッチ数は、正のインデックスを持つ非連続フィボナッチ数の合計として一意に分解できるということです。