Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Information
Science
Fibonacci Sequence is Magic

2014/01/28 tozangezan
はじめに
• シケプリではありません(特に「プリ」が
違う)
• コラムが延々と続く感じです
• Ruby書きたくないのでまともなソース
コードは載せません
• 今回は漸化式で表される数列の計算をし
ます。
扱う漸化式
• 以下の式を扱います

• このうちのkと求める項の番号nが与えら
れるので、anを答える方法を考えます。
• k=2としたものがFibonacci数列です。
• やり方はたくさんあります。
•

(以下、漸化式の係数をいじればす...
関数の再帰を使う
F(n){
if n < K then 1
else
F(n-1)+F(n-2)+…+F(n-k)
}
(注)どの言語でもないので実行できません

• 再帰関数というのは
定義した関数の中に
同じ関数を呼び出す
機構があるもの...
遅い!
• よく考えると、さっきのコードは少なく
とも「1を返す回数」だけ関数が呼ばれて
います
• これは答えの数と一致
• 例えば、50番目のフィボナッチ数は
12586269025で、このプログラムだと数分
はかかりそう
• 計算量はだい...
計算量:指数関数
• 基本的に指数関数はダメです

• 参考
http://www.youtube.com/watch?v=Q4gTV4r0
zRs
• 「F(n)は何度も計算したところで毎回値同
じでは…」という発想だけで高速になりま
す。
関数のメモ化再帰をする
F(n){
if “F(n)計算済み”
then “計算済みの値”
if n < K then 1
else
F(n-1)+F(n-2)+…+F(n-k)
}
(注)どの言語でもないので実行できません

• さっきのもの...
メモ化再帰での計算量
• 関数はnの値あたり1回しか呼び出されない
としてよい
• (正確には何回か呼ばれてるだろうけど最初
の1文だけだしどうでもいい)
• nの値によって関数は1回ずつ呼ばれて計
O(n)
• 関数1回ではK個の数の和を計算...
動的計画法を使う
a[N] # 配列
• 今度は関数を使わず
に、ループをまわす
a*1+=a*2+=…=a*k+=1
だけでかいてみまし
for i in (k+1)..n
た。
a[i]=a[i-1]+a[i-2++…+a*i-k]
• 本...
動的計画法での計算量
• メモ化再帰と同じ
• n回くらいループをまわしていて、 (O(n))
• それぞれではk個の数の和を計算 (O(k))
• 全部まとめると O(nk)
• やっぱりメモ化再帰と同じ
問題
• 以下の数列を考える

• このうちのkと求める項の番号nが与えら
れるので、anを109+7で割ったあまりを答
えよ。
• k ≦ 100
• n ≦ 100 000
• 解答例: さっきのメモ化再帰,動的計画法
問題
• 以下の数列を考える

• このうちのkと求める項の番号nが与えら
れるので、anを109+7で割ったあまりを答
えよ。
• k ≦ 100
• n ≦ 1 000 000 000 000 000 000
• 解答例: さっきのメモ化再...
別世界
• ここから先はコード書くの面倒なのでか
きません。
• 情報科学の試験レベルなら別にこのくら
いでゴールして良いんじゃないでしょう
か。
• ここから先はkが大きいのには対処できま
せんが、nが大きいのに対処できる方法で
す。
行列累乗
• k=2のとき、
• k=3のとき、

• k=4のとき、
行列累乗
• こういう感じの形になるので、anを得るた
めには1を並べたベクトルにn-k回さっきの
ような行列をかければよい。
• 行列のかけ算
• A, A2, A4, A8, A16, A32, …は同じものをかける
処理をすると、全部でO...
行列累乗での計算量
• ということは、行列のかけ算はO(log n)回
行えばよい。
• ここで使う行列はk次正方行列なので1回
のかけ算はO(k3)かかる (定義に従って素直
に計算するしかない)
• ということで全体での計算量はO(k3 l...
問題
• 以下の数列を考える

• このうちのkと求める項の番号nが与えら
れるので、anを109+7で割ったあまりを答
えよ。
• k ≦ 100
• n ≦ 1 000 000 000 000 000 000
• 解答例: 行列累乗
問題
• 以下の数列を考える

• このうちのkと求める項の番号nが与えら
れるので、anを109+7で割ったあまりを答
えよ。
• k ≦ 1 000
• n ≦ 1 000 000 000 000 000 000
• 解答例: 行列累乗
整式の割り算を使う方法
• 実は、この問題の第n項の値は、
「xnをxk-xk-1-xk-2-…-1で割ったあまりの係数
の総和」に等しいです。(証明略)

xnをxk-xk-1-xk-2-…-1で割ったあまりは、x[n/2]を
xk-xk-1...
整式の割り算を使う方法
• k-1次の多項式二つの乗算はO(k2)でできま
す
• この多項式の乗算はO(log n)回呼ばれます

• ということで全体での計算量はO(k2 log n)
です。
参考問題
• http://tdpc.contest.atcoder.jp/tasks/tdpc_fibo
nacci
• けっこう多くの言語で(Rubyでも)解くこと
ができるっぽいです。
• 解答例
http://tdpc.contest....
おまけ
• 整式のかけ算は畳み込みなのでFFTで計算
できてO(k log k)になります。
• が、その整式を割ったあまりの計算がど
うやったらO(k2)から落ちるかわかりませ
ん。
• 誰か教えてください
• あと、今回109+7で割ったあ...
The End
Upcoming SlideShare
Loading in …5
×

情報科学シケスラ Fibonacci

952 views

Published on

情報科学

Published in: Education
  • Be the first to comment

  • Be the first to like this

情報科学シケスラ Fibonacci

  1. 1. Information Science Fibonacci Sequence is Magic 2014/01/28 tozangezan
  2. 2. はじめに • シケプリではありません(特に「プリ」が 違う) • コラムが延々と続く感じです • Ruby書きたくないのでまともなソース コードは載せません • 今回は漸化式で表される数列の計算をし ます。
  3. 3. 扱う漸化式 • 以下の式を扱います • このうちのkと求める項の番号nが与えら れるので、anを答える方法を考えます。 • k=2としたものがFibonacci数列です。 • やり方はたくさんあります。 • (以下、漸化式の係数をいじればすこし一般化できます)
  4. 4. 関数の再帰を使う F(n){ if n < K then 1 else F(n-1)+F(n-2)+…+F(n-k) } (注)どの言語でもないので実行できません • 再帰関数というのは 定義した関数の中に 同じ関数を呼び出す 機構があるものだと 思っておけばよいと 思います。 • 漸化式をそのまま コードに書いたらこ んな感じになります。
  5. 5. 遅い! • よく考えると、さっきのコードは少なく とも「1を返す回数」だけ関数が呼ばれて います • これは答えの数と一致 • 例えば、50番目のフィボナッチ数は 12586269025で、このプログラムだと数分 はかかりそう • 計算量はだいたい O(αn) αは何かの定数 • (Fibonacci数列なら黄金数とか)
  6. 6. 計算量:指数関数 • 基本的に指数関数はダメです • 参考 http://www.youtube.com/watch?v=Q4gTV4r0 zRs • 「F(n)は何度も計算したところで毎回値同 じでは…」という発想だけで高速になりま す。
  7. 7. 関数のメモ化再帰をする F(n){ if “F(n)計算済み” then “計算済みの値” if n < K then 1 else F(n-1)+F(n-2)+…+F(n-k) } (注)どの言語でもないので実行できません • さっきのものに2行書 きたし、無駄に計算 しないようにしまし た。 • かなり速く動くよう になります。 • まだ漸化式から想像 がつくでしょう。
  8. 8. メモ化再帰での計算量 • 関数はnの値あたり1回しか呼び出されない としてよい • (正確には何回か呼ばれてるだろうけど最初 の1文だけだしどうでもいい) • nの値によって関数は1回ずつ呼ばれて計 O(n) • 関数1回ではK個の数の和を計算するので O(k) • これら全部まとめるとO(nk)
  9. 9. 動的計画法を使う a[N] # 配列 • 今度は関数を使わず に、ループをまわす a*1+=a*2+=…=a*k+=1 だけでかいてみまし for i in (k+1)..n た。 a[i]=a[i-1]+a[i-2++…+a*i-k] • 本当はk個の数の和を 求めるのでもループ を使うんですがね。 • コードが短め。
  10. 10. 動的計画法での計算量 • メモ化再帰と同じ • n回くらいループをまわしていて、 (O(n)) • それぞれではk個の数の和を計算 (O(k)) • 全部まとめると O(nk) • やっぱりメモ化再帰と同じ
  11. 11. 問題 • 以下の数列を考える • このうちのkと求める項の番号nが与えら れるので、anを109+7で割ったあまりを答 えよ。 • k ≦ 100 • n ≦ 100 000 • 解答例: さっきのメモ化再帰,動的計画法
  12. 12. 問題 • 以下の数列を考える • このうちのkと求める項の番号nが与えら れるので、anを109+7で割ったあまりを答 えよ。 • k ≦ 100 • n ≦ 1 000 000 000 000 000 000 • 解答例: さっきのメモ化再帰,動的計画法
  13. 13. 別世界 • ここから先はコード書くの面倒なのでか きません。 • 情報科学の試験レベルなら別にこのくら いでゴールして良いんじゃないでしょう か。 • ここから先はkが大きいのには対処できま せんが、nが大きいのに対処できる方法で す。
  14. 14. 行列累乗 • k=2のとき、 • k=3のとき、 • k=4のとき、
  15. 15. 行列累乗 • こういう感じの形になるので、anを得るた めには1を並べたベクトルにn-k回さっきの ような行列をかければよい。 • 行列のかけ算 • A, A2, A4, A8, A16, A32, …は同じものをかける 処理をすると、全部でO(log n)回で求めら れる • ほかのものが得たいときは、例えば A21= A × A4 × A16 などと2進数っぽくする。
  16. 16. 行列累乗での計算量 • ということは、行列のかけ算はO(log n)回 行えばよい。 • ここで使う行列はk次正方行列なので1回 のかけ算はO(k3)かかる (定義に従って素直 に計算するしかない) • ということで全体での計算量はO(k3 log n)
  17. 17. 問題 • 以下の数列を考える • このうちのkと求める項の番号nが与えら れるので、anを109+7で割ったあまりを答 えよ。 • k ≦ 100 • n ≦ 1 000 000 000 000 000 000 • 解答例: 行列累乗
  18. 18. 問題 • 以下の数列を考える • このうちのkと求める項の番号nが与えら れるので、anを109+7で割ったあまりを答 えよ。 • k ≦ 1 000 • n ≦ 1 000 000 000 000 000 000 • 解答例: 行列累乗
  19. 19. 整式の割り算を使う方法 • 実は、この問題の第n項の値は、 「xnをxk-xk-1-xk-2-…-1で割ったあまりの係数 の総和」に等しいです。(証明略) xnをxk-xk-1-xk-2-…-1で割ったあまりは、x[n/2]を xk-xk-1-xk-2-…-1で割ったあまりを2乗し(nが奇 数ならさらにxをかける)、その式をxk-xk-1-xk2-…-1で割ったあまりを求めればよいです。
  20. 20. 整式の割り算を使う方法 • k-1次の多項式二つの乗算はO(k2)でできま す • この多項式の乗算はO(log n)回呼ばれます • ということで全体での計算量はO(k2 log n) です。
  21. 21. 参考問題 • http://tdpc.contest.atcoder.jp/tasks/tdpc_fibo nacci • けっこう多くの言語で(Rubyでも)解くこと ができるっぽいです。 • 解答例 http://tdpc.contest.atcoder.jp/submissions/1193 05 (C++, 48行)
  22. 22. おまけ • 整式のかけ算は畳み込みなのでFFTで計算 できてO(k log k)になります。 • が、その整式を割ったあまりの計算がど うやったらO(k2)から落ちるかわかりませ ん。 • 誰か教えてください • あと、今回109+7で割ったあまりを求めた のは答えが大きくなりすぎるからです。
  23. 23. The End

×