Successfully reported this slideshow.
Your SlideShare is downloading. ×

解説:おおきな数を作った

Ad

解説:おおきな数を作った
技術室奥プログラミングコンテスト 問題G

Ad

問題を整理する
• 大きな数があたえられる
• この数を適当にぶった切っていって、
右から数が昇順に並ぶようにする
• 「最大の数の桁数」を最小化する

Ad

基本方針
• 与えられる数を文字列と見たときの、先頭からi番目について、
「i+1番目からN番目までの文字列で表される数」を作る数の組の
中で、最大の数の桁数の最小値をdp[i]として記憶する
• iを上から下に変化させていって、DPする

Ad

Ad

Ad

Ad

Ad

Ad

Ad

Loading in …3
×

Check these out next

1 of 10 Ad
1 of 10 Ad
Advertisement

More Related Content

Advertisement

解説:おおきな数を作った

  1. 1. 解説:おおきな数を作った 技術室奥プログラミングコンテスト 問題G
  2. 2. 問題を整理する • 大きな数があたえられる • この数を適当にぶった切っていって、 右から数が昇順に並ぶようにする • 「最大の数の桁数」を最小化する
  3. 3. 基本方針 • 与えられる数を文字列と見たときの、先頭からi番目について、 「i+1番目からN番目までの文字列で表される数」を作る数の組の 中で、最大の数の桁数の最小値をdp[i]として記憶する • iを上から下に変化させていって、DPする
  4. 4. 基本方針 • DPは2種類の方法で進める • 1種類目 そのまま桁を一つ進める。それに応じて桁数も増やす dp[i-1] = min(dp[i]+1,dp[i-1] )
  5. 5. 基本方針 • 2種類目 i番目を数の区切りとして考え、次の数の区切りを探す 「i-dp[i]+1番目からdp[i]個の文字列の数」と 「i+1番目からdp[i]個の文字列の数」を比較し、 前者が前者より大きければ、dp[i-dp[i]] = min(dp[i], dp[i-dp[i]] ) 後者が前者以上なら、dp[i-dp[i]-1] = min(dp[i]+1, dp[i-dp[i]-1] ) • なお、この操作はi+1番目の文字が0であるときに行ってはならない。 そうしないと、先頭の数が0の数字を許すことになってしまう。
  6. 6. 部分点解法 • これを愚直に実装する • DPを一個進めるのに、文字列の比較部分で最大O(N)かかる • DPはN回進めるので、O(N^2)になる
  7. 7. 満点解法 • 文字列の比較を高速化したい • Suffix Arrayを使おう! • i番目のsuffixとj番目のsuffixの大小関係、 その二つのLCPがわかると、 比較する桁数がLCP以下ならば二つの数は等しく、 そうでなければ、二つのsuffixの大小関係が そのまま数の大小関係として使える。
  8. 8. 満点解法 • Suffix Arrayはどうやって求める? 制約から考えてO(N)のSAIS一択 • 任意の二つのsuffixのLCPはどうやって求める? 順番が隣り合うsuffixのLCPをあらかじめ求めておき、RMQする。 RMQのデータは変更されないので、SparseTableとかがお勧め 隣り合うLCPを求めるのにO(N)、 RMQの構築にO(NlogN)、RMQの取得がO(1)となる
  9. 9. 満点解法 • 文字列の比較部分がO(1)になった! • DPでO(N) • よって全体オーダーは、O(NlogN)になる
  10. 10. おわりに • ローリングハッシュとか名前くらいは知ってたけど知りません (いっぱい通された)

×