Upgrade to Pro — share decks privately, control downloads, hide ads and more …

HUIT新歓2024「競技プログラミング、やってみませんか?」

Slephy
April 05, 2024

 HUIT新歓2024「競技プログラミング、やってみませんか?」

北大IT研究会(HUIT)の2024年度新歓で使用した資料。
競技プログラミングの入門を促す内容。

Slephy

April 05, 2024
Tweet

Other Decks in Programming

Transcript

  1. 自己紹介 • Handle: Slephy • 所属: 北海道大学 工学部 情報エレクトロニクス学科 •

    学年: 学部4年 • 出身: 札幌 • 趣味: 競技プログラミング(4年目) • 好きな言語: C++ • 好きなポケモン: パモ, ワンパチ https://zukan.pokemon.co.jp/detail/0921 かわいい 私のアイコン
  2. プログラミング入門の次は何をする? プログラミング 入門 アプリ開発 Web開発 ゲーム開発 機械学習 ハードウェア 開発 自然言語処理

    ITの世界は広くて深い 入門を終えたばかりの初心者は挫折しやすい 変数 if for 飛躍が大きい
  3. 競技プログラミングとは -順位の付け方- G 600pt 問題 F 525pt 問題 E 500pt

    問題 D 400pt 問題 C 350pt 問題 B 200pt 問題 A 100pt 問題 複数の問題に2時間程度で挑戦する”コンテスト”が開催される 正解した問題の合計得点が高い人が良い順位になる 同点ならば早く回答した人が良い順位になる
  4. AtCoder Beginner Contest とは • AtCoder Beginner Contest • 略してABC

    • 毎週土曜(もしくは日曜)の午後9時から開催 • だれでも参加可能 • 100分間で7問を解いて点数や正答するまでの早さを競う • 週末夜にもかかわらず約10000人が参加する人気コンテスト
  5. まずは工夫が必要ない簡単な問題 1 2 3 4 5 6 7 8 9

    2 4 6 8 10 12 14 16 18 3 6 9 12 15 18 21 24 27 4 8 12 16 20 24 28 32 36 5 10 15 20 25 30 35 40 45 6 12 18 24 30 36 42 48 54 7 14 21 28 35 42 49 56 63 8 16 24 32 40 48 56 64 72 9 18 27 36 45 54 63 72 81 N = 15 Input Yes Output N = 38 Input No Output 例 整数 𝑵𝑵 が与えられる。 𝑵𝑵 が九九表に含まれる数かどうかを判定せよ。 問題 参考: https://atcoder.jp/contests/abc144/tasks/abc144_b
  6. なぜこのプログラムは遅いのか • 現代のコンピュータは基本的な計算を1秒間におよそ𝟏𝟏𝟏𝟏𝟖𝟖回できる • 𝟏𝟏 ≤ 𝒂𝒂 ≤ 𝟏𝟏𝟎𝟎𝟔𝟔, 𝟏𝟏

    ≤ 𝒃𝒃 ≤ 𝟏𝟏𝟎𝟎𝟔𝟔 の範囲を全て調べるためには 𝟏𝟏𝟎𝟎𝟏𝟏𝟏𝟏回程度の計算が必要 • 先ほどの方法では Pythonで数時間かかってしまう パソコンは高速に計算することが可能 しかしどんな問題でも一瞬で解けるわけではない Point 原因
  7. より良いアルゴリズム 条件を満たす可能性がある 𝒂𝒂, 𝒃𝒃 をすべて検証する 従来のアルゴリズム 条件を満たす可能性がある 𝒂𝒂 をすべて検証する 𝒂𝒂

    を決めれば、それに対応する 𝒃𝒃 が条件を満たすかはすぐに判定できる 新しいアルゴリズム 𝑵𝑵 = 𝒂𝒂𝒂𝒂 より 𝒃𝒃 = 𝑵𝑵 𝒂𝒂 なので、 𝒂𝒂 を決めれば 𝒃𝒃 の値は決まる 重要な考察 𝟏𝟏𝟎𝟎𝟏𝟏𝟏𝟏回 𝟏𝟏𝟎𝟎𝟔𝟔回
  8. 高速化の必要がある問題 a = 3, b = 4 Input 81 Output

    a = 7, b = 16 Input 601 Output 34 = 81 716 = 33,232,930,569,601 自然数 𝒂𝒂, 𝒃𝒃 が与えられる。𝒂𝒂𝒃𝒃 の下3桁を出力せよ。 ただし 𝟏𝟏 ≤ 𝒃𝒃 ≤ 𝟏𝟏𝟎𝟎𝟏𝟏𝟏𝟏 であり、𝒃𝒃 は非常に大きな値かもしれない。 問題 例
  9. 素朴なアルゴリズム 71 = 7 72 = 71 × 71 =

    7 × 7 = 49 73 = 72 × 71 = 49 × 7 = 343 74 = 73 × 71 = 343 × 7 = 2,401 ⋮ 716 = 715 × 71 = 4,747,561,509,943 × 7 = 33,232,930,569,601 𝒃𝒃回の計算 a = 7, b = 16 Input ひとつひとつ 順番に求めていく アルゴリズム
  10. 問題点①の解決策 桁数の大きな掛け算はパソコンでも時間がかかる 問題点① 下三桁だけで計算すればよい 解決策 1234 ×5678 9872 8638 7404

    6170 7006652 234 ×678 1872 1638 1404 158652 下三桁だけを抜き出して計算しても 答えは変わらない 計算途中でも下三桁以外の情報は 捨ててよい 証明略
  11. 解決策①を適用した様子 71 ≡ 7 72 ≡ 71 × 71 ≡

    7 × 7 ≡ 49 73 ≡ 72 × 71 ≡ 49 × 7 ≡ 343 74 ≡ 73 × 71 ≡ 343 × 7 ≡ 2,401 ≡ 401 ⋮ 716 ≡ 715 × 71 ≡ 943 × 7 ≡ 9,601 ≡ 601 a = 7, b = 16 Input 以下、法を1000とする 大きな数を使わずに問題を扱うことに成功
  12. 問題点②の解決策(𝒃𝒃 = 𝟐𝟐𝒌𝒌 のとき) 71 ≡ 7 72 ≡ 71

    × 71 ≡ 7 × 7 ≡ 49 74 ≡ 72 × 72 ≡ 49 × 49 ≡ 2,401 ≡ 401 78 ≡ 74 × 74 ≡ 401 × 401 ≡ 160,801 ≡ 801 716 ≡ 78 × 78 ≡ 801 × 801 ≡ 640,601 ≡ 601 a = 7, b = 16 Input 以下、法を1000とする 繰り返し2乗することで 𝒂𝒂𝒃𝒃を 𝒌𝒌 回の掛け算で求められる
  13. 問題点②の解決策(𝒃𝒃 ≠ 𝟐𝟐𝒌𝒌 のとき) a = 7, b = 21

    Input 以下、法を1000とする 721 ≡ 716 × 74 × 71 ≡ 601 × 401 × 7 ≡ 1,687,007 ≡ 7 𝒃𝒃 = 𝟐𝟐𝒌𝒌のときの結果を利用することで答えを高速に求められる 71 ≡ 7 72 ≡ 71 × 71 ≡ 49 74 ≡ 72 × 72 ≡ 401 78 ≡ 74 × 74 ≡ 801 716 ≡ 78 × 78 ≡ 601 16 8 4 2 1 1 0 1 0 1 𝟐𝟐𝟐𝟐 = 𝟏𝟏𝟏𝟏𝟏𝟏𝟏𝟏𝟏𝟏(𝟐𝟐) bを2進法で表すと bの作り方が分かる
  14. 問題点②の解決策 𝟏𝟏 ≤ 𝒃𝒃 ≤ 𝟏𝟏𝟎𝟎𝟏𝟏𝟏𝟏 < 𝟐𝟐𝟔𝟔𝟔𝟔 なので 𝒌𝒌

    = 𝟔𝟔𝟔𝟔 まで計算しておけばOK 数十から数百回の計算で答えを求められるので 0.1秒以内にはプログラムが終了する Pythonでの実装を見てみよう DEMO
  15. 本問題のまとめ 71 72 74 78 716 • 「1つ先→2つ先→4つ先→… 」のようにどんどんと倍を求めて 高速化するアルゴリズムを”ダブリング”という

    • その中でも今回紹介したものを特別に”繰り返し二乗法”という • 名前の付いたアルゴリズムを知ることで 発想が難しいアルゴリズムを構築する足掛かりになる
  16. 幅優先探索 深さ優先探索 二分探索 Euler Tour Binary Indexed Tree Dynamic Programming

    Rolling Hash Segment Tree Dijkstra's algorithm Bostan-Mori 法 Monotone minim kd Tree 累積和 Low link owest Common Ancestor Minimum-cost Flow Slope Trick 2-SAT G 600pt 問題 F 525pt 問題 E 500pt 問題 D 400pt 問題 B 200pt 問題 A 100pt 問題 C 350pt 問題 まだまだ広がる競技プログラミングの世界
  17. 競技プログラミングを 始めたいと思ったら • まずはAtCoderのアカウントを作成する • AtCoder Problems から過去問を解いてみる • ABC

    の日程を確認して参加する • 競技プログラミングの入門書を読む(図書館にも蔵書有) • HUITで競技プログラミングをやっている人に話を聞く • (プログラミングをやったことがない人はこちらから) C++入門 AtCoder Programming Guide for beginners (APG4b)