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.
SuperCon2010予選問題アルゴリズム解説<br />3S 大城泰平<br />2010/06/21(月)<br />
Problem Statement<br />(横, 縦)=(n, 2)の長方形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力<br />BoundaryCondition<br />入力...
n=1の場合 (1通り)<br />n=2の場合(2通り)<br />n=3の場合 (3通り)<br />n=4の場合 (5通り)<br />n=5の場合 (8通り)<br />まずは列挙してみる<br />
n=6の場合 (13通り)<br />表にしてみると…<br />あれ?なんかフィボナッチ数列っぽいかも?<br />まずは列挙してみる<br />
n=6の敷き詰め方の右端に注目してみる<br />二種類に分類出来る<br />考察1<br />B<br />A<br />
Aグループ<br />右端のブロックは「全て」縦に1つ<br />⇒ Aグループの数 = 右端以外の部分を敷き詰める通り数<br />これはn=5の時の通り数に等しい<br />Bグループ<br />右端のブロックは「全て」横に2つ<br />...
これはn=6に限らず、一般に成り立つので<br />(n=iの通り数) = (n=i-1の通り数) + (n=i-2の通り数)<br />n=iの時の通り数をFiと置くと<br />Fi=1   (i=1)2       (i=2)Fi−1+F...
Problem Statement<br />(横, 縦)=(m, 3)の長方形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力<br />BoundaryCondition<br />入力...
縦の長さが奇数<br />敷き詰める板の面積は2cm2 より偶数<br />mが奇数の時、(奇数)×(奇数)=(奇数)より面積も奇数<br />偶数の整数倍は偶数なので、どうやっても敷き詰められない⇔通り数=0<br />これ以降はmが偶数だと...
右端の形を全通り列挙<br />それぞれの形について考察する<br />形2, 3, 4<br />mが偶数なので図形の面積が奇数になる<br />  ⇒このように敷き詰めることは出来ない<br />考察2<br />
形6<br />まず右端の出っ張ったところに横向きに配置<br />上下に隅が出来るのでそこに横向きに配置<br />mが2小さくなった形6がまた現れる<br />これを繰り返すとm=2の形6になる<br />m=2の形6を敷き詰めることは出来...
残ったのは形1, 5, 7<br />形5と形7は上下を反転させた形である<br />形5と形7を敷き詰める通り数は等しい<br />m=iの時の形1を敷き詰める通り数をAiとおく<br />m=iの時の形5, 7を敷き詰める通り数をBiとおく...
Aiについて考察<br />m=i-2の形1に右端がくっついている形<br />m=i-2の形5に右端がくっついている形<br />m=i-2の形7に右端がくっついている形<br />以上の3通りが考えられる<br /> <br />考察5<b...
a.m=i-2の形1に右端がくっついている形<br />この右端を敷き詰めるパターンを列挙すると<br />       <br />の3パターン存在する<br />従って、a. による敷き詰め方の通り数は<br />(右端の通り数) × (右...
b.m=i-2の形5に右端がくっついている形<br />この右端を敷き詰めるパターンを列挙すると<br />       <br />の4パターン存在する<br />しかし、一番左以外の敷き詰め方は<br />       ⇒       のよ...
従って、a. と被らない右端の敷き詰め方は   のみ<br />⇒ b. による敷き詰め方の通り数はBi−2<br />c. は b. を上下反転しただけなので、敷き詰め方は同じ<br />⇒ c. による敷き詰め方の通り数もBi−2<br /...
Biについて考察<br />m=i-2の形1に右端がくっついている形<br />右端の敷き詰め方は  のみ<br />⇒ a. による敷き詰め方の通り数はAi−2<br />m=i-2の形5に右端がくっついている形<br />右端の敷き詰め方は...
m=i-2の形7に右端がくっついている形<br />右端の敷き詰め方は   のみ<br />a. と同じ形に分けることが出来る<br /> ⇒ c. により敷き詰める事はできない<br />以上より<br />Bi=Ai−2+Bi−2<br /...
    を敷き詰める通り数をAm<br />    を敷き詰める通り数をBmと置いたとき<br />Am=033Am−2+2Bm−2     (m is odd)(m=2)       (otherwise)<br />Bm=01Am−2+Bm...
Problem Statement<br />(横, 縦)=(m, 3)の長方形と(n, 2)の長方形を底辺が一直線上にあるように横に並べた形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力...
mが奇数の場合<br />図形の面積が奇数になるので、敷き詰める通り数 = 0<br />これ以降はmが偶数だと仮定<br />敷き詰め方は以下の2パターンに分類出来る<br />考察1<br />B<br />A<br />
Aパターン「分けられる」<br />左の図形を敷き詰める通り数はAm<br />右の図形を敷き詰める通り数はFn<br />従ってAパターンを敷き詰める通り数は AmFn<br />Bパターン「分けられない」<br />分けられない場合は下図の...
Bパターン「分けられない」<br />左の図形を敷き詰める通り数はBm<br />右の図形を敷き詰める通り数はFn−1<br />従ってBパターンを敷き詰める通り数は BmFn−1<br />これより       を敷き詰める通り数は<br /...
n=1の時 AmF1+BmF0<br />だったので…<br />F0が定義されていない!<br />F0に拡張する<br />F2にも同じ漸化式を適用出来るとすると<br />F2=F1+F0<br />                   ...
従って<br />同様に、数列AとBも0に拡張すると<br />注意2<br />Fn=1      (n=0)1          (n=1)Fn−1+Fn−2 (otherwise)<br /> <br />Am=013Am−2+2Bm−2...
kの剰余を取る<br />a mod k+b mod k≡a+b   (mod k)<br />a mod kb mod k≡ab      (mod k)<br />数列の値を求める上で用いる演算について上記の式が成り立つので、オーバーフロー...
数列の値を求める<br />愚直な実装<br />n回ループしてFnを、m回ループしてAm, Bmを求める<br />時間計算量 O(m+n)<br />600000回繰り返すので<br />600000(m+n) ≦ 39320400000(...
高速化を考える<br />最初にF, A, Bの値を一度計算してテーブルを作る<br />そのままの値ではオーバーフローを起こしてしまう<br />kの値がクエリ毎に変わるので剰余を取った値も保存出来ない<br />⇒ テーブルを作るのは難しい...
漸化式を行列で書き表すことが出来る<br />ところで、Am−2Bm−2=3211Am−4Bm−4 を代入すると<br />AmBm=32112Am−4Bm−4<br />これをm2回繰り返すと<br />AmBm=3211m2A0B0=321...
数列Fについても                          とすることで<br />FnFn−1=1110n10<br />と行列で表すことが出来る  (F−1=0を用いた)<br />係数行列の累乗を高速に求めることができれば、数列の...
とある行列Dの累乗計算高速化<br />Dnを高速に求めたい<br />nが2の冪乗の場合<br />D×D=D2 (掛け算1回)<br />D2×D2=D4 (掛け算2回)<br />D4×D4=D8 (掛け算3回)<br />D8×D8=D...
nが2の冪乗ではない場合<br />nを2進表記してみる<br /> 例: n=22 -> (10110)2<br />nは2の冪乗の和だということが分かる<br /> 例: 22=(10110)2=24+22+21<br />指数部の足し算は...
指数nのビットが1の所だけ掛け算を行う<br />D16二乗 D8二乗 D4二乗 D2二乗 D1<br />(22)10 = ( 1          0         1         1         0  )2<br />     ...
行列累乗を用いた全体の時間計算量<br />600000lgn+lgm=600000lgnm<br />≦18000000 (1800万)<br />I/Oに時間がかかるが、この方法だとm, nが大きくなっても比較的高速に解を出すことが出来る<...
その他の高速化<br />剰余算の回数を出来るだけ少なくする<br />除算(剰余算)は加減乗算に比べて圧倒的に時間がかかる<br />2の除算や剰余算にはビット演算を使う<br />最適化オプション(-O2)が使われない<br />if分岐を...
終わり<br />
Upcoming SlideShare
Loading in …5
×

SuperCon2010予選アルゴリズム解説

2,420 views

Published on

予選問題のアルゴリズム解説。

Published in: Lifestyle, News & Politics
  • Be the first to comment

  • Be the first to like this

SuperCon2010予選アルゴリズム解説

  1. 1. SuperCon2010予選問題アルゴリズム解説<br />3S 大城泰平<br />2010/06/21(月)<br />
  2. 2. Problem Statement<br />(横, 縦)=(n, 2)の長方形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力<br />BoundaryCondition<br />入力されるn, kの数は600000個<br />1≦n≦32767<br />2≦k≦32767<br />問A<br />
  3. 3. n=1の場合 (1通り)<br />n=2の場合(2通り)<br />n=3の場合 (3通り)<br />n=4の場合 (5通り)<br />n=5の場合 (8通り)<br />まずは列挙してみる<br />
  4. 4. n=6の場合 (13通り)<br />表にしてみると…<br />あれ?なんかフィボナッチ数列っぽいかも?<br />まずは列挙してみる<br />
  5. 5. n=6の敷き詰め方の右端に注目してみる<br />二種類に分類出来る<br />考察1<br />B<br />A<br />
  6. 6. Aグループ<br />右端のブロックは「全て」縦に1つ<br />⇒ Aグループの数 = 右端以外の部分を敷き詰める通り数<br />これはn=5の時の通り数に等しい<br />Bグループ<br />右端のブロックは「全て」横に2つ<br />⇒ Bグループの数 = 右端以外の部分を敷き詰める通り数<br />これはn=4の時の通り数に等しい<br />これより<br />(n=6の通り数)=(n=5の通り数)+(n=4の通り数)<br />考察2<br />
  7. 7. これはn=6に限らず、一般に成り立つので<br />(n=iの通り数) = (n=i-1の通り数) + (n=i-2の通り数)<br />n=iの時の通り数をFiと置くと<br />Fi=1   (i=1)2       (i=2)Fi−1+Fi−2 (otherwise)<br />やっぱりフィボナッチ数列だった!<br /> (一般のフィボナッチ数列と1つずれていることに注意。)<br /> <br />A解法<br />
  8. 8. Problem Statement<br />(横, 縦)=(m, 3)の長方形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力<br />BoundaryCondition<br />入力されるm, kの数は600000個<br />1≦m≦32767<br />2≦k≦32767<br />問B<br />
  9. 9. 縦の長さが奇数<br />敷き詰める板の面積は2cm2 より偶数<br />mが奇数の時、(奇数)×(奇数)=(奇数)より面積も奇数<br />偶数の整数倍は偶数なので、どうやっても敷き詰められない⇔通り数=0<br />これ以降はmが偶数だと仮定して話を進める<br />問Aと同じように、右端に注目してみる<br />長方形だけでなく、いろいろな形の右端について考える<br />最長の行と最短の行の差が2未満という条件を付けると問Aは長方形以外に存在し得なかったが、問Bでは存在し得る<br />->まずは「右端の形」について考察する<br /> <br />考察1<br />
  10. 10. 右端の形を全通り列挙<br />それぞれの形について考察する<br />形2, 3, 4<br />mが偶数なので図形の面積が奇数になる<br />  ⇒このように敷き詰めることは出来ない<br />考察2<br />
  11. 11. 形6<br />まず右端の出っ張ったところに横向きに配置<br />上下に隅が出来るのでそこに横向きに配置<br />mが2小さくなった形6がまた現れる<br />これを繰り返すとm=2の形6になる<br />m=2の形6を敷き詰めることは出来ない<br />⇒全てのmに於いて形6を敷き詰めることは出来ない<br />考察3<br />
  12. 12. 残ったのは形1, 5, 7<br />形5と形7は上下を反転させた形である<br />形5と形7を敷き詰める通り数は等しい<br />m=iの時の形1を敷き詰める通り数をAiとおく<br />m=iの時の形5, 7を敷き詰める通り数をBiとおく<br />数列A, Bについて数式を考える<br />最終的に要求されている答えはAm<br /> <br />考察4<br />
  13. 13. Aiについて考察<br />m=i-2の形1に右端がくっついている形<br />m=i-2の形5に右端がくっついている形<br />m=i-2の形7に右端がくっついている形<br />以上の3通りが考えられる<br /> <br />考察5<br />
  14. 14. a.m=i-2の形1に右端がくっついている形<br />この右端を敷き詰めるパターンを列挙すると<br />       <br />の3パターン存在する<br />従って、a. による敷き詰め方の通り数は<br />(右端の通り数) × (右端以外の場所の通り数) より<br />3Ai−2となる<br /> <br />考察6<br />
  15. 15. b.m=i-2の形5に右端がくっついている形<br />この右端を敷き詰めるパターンを列挙すると<br />       <br />の4パターン存在する<br />しかし、一番左以外の敷き詰め方は<br />       ⇒       のように、a. パターンと同じ形<br />に分けることができてしまう ⇒ a.で既に数えている!<br />考察7<br />
  16. 16. 従って、a. と被らない右端の敷き詰め方は   のみ<br />⇒ b. による敷き詰め方の通り数はBi−2<br />c. は b. を上下反転しただけなので、敷き詰め方は同じ<br />⇒ c. による敷き詰め方の通り数もBi−2<br />Ai = (a.の通り数) + (b.の通り数) + (c.の通り数)<br /> より<br />Ai=3Ai−2+2Bi−2<br /> <br />考察8<br />
  17. 17. Biについて考察<br />m=i-2の形1に右端がくっついている形<br />右端の敷き詰め方は  のみ<br />⇒ a. による敷き詰め方の通り数はAi−2<br />m=i-2の形5に右端がくっついている形<br />右端の敷き詰め方は の2通り<br />前者はa. と同じ形に分けることができる<br />⇒ b. による敷き詰め方の通り数はBi−2<br /> <br />考察9<br />
  18. 18. m=i-2の形7に右端がくっついている形<br />右端の敷き詰め方は   のみ<br />a. と同じ形に分けることが出来る<br /> ⇒ c. により敷き詰める事はできない<br />以上より<br />Bi=Ai−2+Bi−2<br />(ここではBiをm=iの時の形5を敷き詰める通り数として考えたが、形7を敷き詰める通り数として考える場合はc. により敷き詰める通り数がBi−2、b. により敷き詰める通り数が0になる。)<br /> <br />考察10<br />
  19. 19.     を敷き詰める通り数をAm<br />    を敷き詰める通り数をBmと置いたとき<br />Am=033Am−2+2Bm−2     (m is odd)(m=2)       (otherwise)<br />Bm=01Am−2+Bm−2      (m is odd)(m=2)        (otherwise)<br /> <br />B解法<br />
  20. 20. Problem Statement<br />(横, 縦)=(m, 3)の長方形と(n, 2)の長方形を底辺が一直線上にあるように横に並べた形に(1, 2)(2, 1)の長方形を敷き詰める<br />敷き詰め方のパターン数をkで割った余りを出力<br />BoundaryCondition<br />入力されるm,n, kの数は600000個<br />1≦m≦32767<br />1≦n≦32767<br />2≦k≦32767<br />問C<br />
  21. 21. mが奇数の場合<br />図形の面積が奇数になるので、敷き詰める通り数 = 0<br />これ以降はmが偶数だと仮定<br />敷き詰め方は以下の2パターンに分類出来る<br />考察1<br />B<br />A<br />
  22. 22. Aパターン「分けられる」<br />左の図形を敷き詰める通り数はAm<br />右の図形を敷き詰める通り数はFn<br />従ってAパターンを敷き詰める通り数は AmFn<br />Bパターン「分けられない」<br />分けられない場合は下図の緑に必ず配置される<br />これ以外の「分けられない」配置だと、右側の図形の面積が奇数になる<br /> <br />考察2<br />
  23. 23. Bパターン「分けられない」<br />左の図形を敷き詰める通り数はBm<br />右の図形を敷き詰める通り数はFn−1<br />従ってBパターンを敷き詰める通り数は BmFn−1<br />これより       を敷き詰める通り数は<br />AmFn+BmFn−1<br /> <br />C解法<br />
  24. 24. n=1の時 AmF1+BmF0<br />だったので…<br />F0が定義されていない!<br />F0に拡張する<br />F2にも同じ漸化式を適用出来るとすると<br />F2=F1+F0<br />                                         F0=F2−F1=2−1=1<br /> <br />注意1<br />Fn=1      (n=1)2          (n=2)Fn−1+Fn−2 (otherwise)<br /> <br />
  25. 25. 従って<br />同様に、数列AとBも0に拡張すると<br />注意2<br />Fn=1      (n=0)1          (n=1)Fn−1+Fn−2 (otherwise)<br /> <br />Am=013Am−2+2Bm−2     (m is odd)(m=0)       (otherwise)<br /> <br />Bm=00Am−2+Bm−2      (m is odd)(m=0)        (otherwise)<br /> <br />
  26. 26. kの剰余を取る<br />a mod k+b mod k≡a+b   (mod k)<br />a mod kb mod k≡ab      (mod k)<br />数列の値を求める上で用いる演算について上記の式が成り立つので、オーバーフローしない内にこまめに剰余を取っておく<br /> <br />実装1<br />
  27. 27. 数列の値を求める<br />愚直な実装<br />n回ループしてFnを、m回ループしてAm, Bmを求める<br />時間計算量 O(m+n)<br />600000回繰り返すので<br />600000(m+n) ≦ 39320400000(393億)<br />m, nが大きくなると計算に時間がかかる<br /> <br />実装2<br />
  28. 28. 高速化を考える<br />最初にF, A, Bの値を一度計算してテーブルを作る<br />そのままの値ではオーバーフローを起こしてしまう<br />kの値がクエリ毎に変わるので剰余を取った値も保存出来ない<br />⇒ テーブルを作るのは難しい<br />漸化式を眺めてみる<br /> Am=3Am−2+2Bm−2Bm=Am−2+Bm−2     <br /> <br />実装3<br />
  29. 29. 漸化式を行列で書き表すことが出来る<br />ところで、Am−2Bm−2=3211Am−4Bm−4 を代入すると<br />AmBm=32112Am−4Bm−4<br />これをm2回繰り返すと<br />AmBm=3211m2A0B0=3211m210<br /> <br />実装4<br /> Am=3Am−2+2Bm−2Bm=Am−2+Bm−2        ⇒   AmBm=3211Am−2Bm−2<br /> <br />
  30. 30. 数列Fについても とすることで<br />FnFn−1=1110n10<br />と行列で表すことが出来る (F−1=0を用いた)<br />係数行列の累乗を高速に求めることができれば、数列の値も高速に求めることができるが…<br /> <br />実装5<br /> Fn=Fn−1+Fn−2Fn−1=Fn−1+0Fn−2     <br /> <br />
  31. 31. とある行列Dの累乗計算高速化<br />Dnを高速に求めたい<br />nが2の冪乗の場合<br />D×D=D2 (掛け算1回)<br />D2×D2=D4 (掛け算2回)<br />D4×D4=D8 (掛け算3回)<br />D8×D8=D16 (掛け算4回)<br /> のようにして、O(lgn)で求まる<br /> <br />実装6<br />
  32. 32. nが2の冪乗ではない場合<br />nを2進表記してみる<br /> 例: n=22 -> (10110)2<br />nは2の冪乗の和だということが分かる<br /> 例: 22=(10110)2=24+22+21<br />指数部の足し算はそれぞれの掛け算に分解出来る<br /> 例: D22=D24+22+21=D24×D22×D21<br /> <br />実装7<br />
  33. 33. 指数nのビットが1の所だけ掛け算を行う<br />D16二乗 D8二乗 D4二乗 D2二乗 D1<br />(22)10 = ( 1 0 1 1 0 )2<br />     D16 × D4 × D2 = D22<br />時間計算量 O(lgn)<br /> <br />実装8<br />
  34. 34. 行列累乗を用いた全体の時間計算量<br />600000lgn+lgm=600000lgnm<br />≦18000000 (1800万)<br />I/Oに時間がかかるが、この方法だとm, nが大きくなっても比較的高速に解を出すことが出来る<br /> <br />実装9<br />
  35. 35. その他の高速化<br />剰余算の回数を出来るだけ少なくする<br />除算(剰余算)は加減乗算に比べて圧倒的に時間がかかる<br />2の除算や剰余算にはビット演算を使う<br />最適化オプション(-O2)が使われない<br />if分岐をできるだけ少なくする<br />分岐には時間がかかる<br />行列の乗算を工夫してみる<br />実装10<br />
  36. 36. 終わり<br />

×