Slide 1

Slide 1 text

Project Euler の話 @nozma 2019-04-05

Slide 2

Slide 2 text

最近AtCoder はじめました まだクソザコナメクジ。 2 / 40

Slide 3

Slide 3 text

実は深刻な問題があります 3 / 40

Slide 4

Slide 4 text

R が使えない… 4 / 40

Slide 5

Slide 5 text

R が使えない…!! 5 / 40

Slide 6

Slide 6 text

R を!!!!!!!!!! 使わせろ!!!!!!! 6 / 40

Slide 7

Slide 7 text

プロコンあるある Rが使えない(重要) バージョンが古い 好きなライブラリを使えない Rが使えない(重要) 仕方ないのでC++で解いてます 7 / 40

Slide 8

Slide 8 text

Project Euler そんな私に 8 / 40

Slide 9

Slide 9 text

論文を沢山書いたおじさんです。 誰? 9 / 40

Slide 10

Slide 10 text

何? 数学の問題集です。 コンピュータを用いて計算することが想定されています。 10 / 40

Slide 11

Slide 11 text

Project Euler のここがすごい ルールが簡単 n桁の数字を解答欄に書き込むだけ(n=チョット) 時間に制限がない 1分以内に解けるように設計されている(one-minute rule) ググっても良い むしろ推奨されている 11 / 40

Slide 12

Slide 12 text

Project Euler のここがすごい (たまに)解説PDFがある (実際あんまりない) フォーラムがある 時間をかけて解く -> フォーラムで賢いやり方を学ぶというのが一般的 言語に制限がない 手元で実行なので当然 12 / 40

Slide 13

Slide 13 text

言語に制限がない!!! 13 / 40

Slide 14

Slide 14 text

どんな言語が使われているのか? AtCoderとProject Eulerでそれぞれ集計してみました。 14 / 40

Slide 15

Slide 15 text

AtCoder のランキング APIがあったのでそこからデータ取得 kenkoooo/AtCoderProblems: Problem manager for AtCoder users jsonをrlistパッケージで読み込んで加工 次の項目を計算してグラフを作成 ユーザー数 ... ACが1件以上あればユーザとカウント AC平均 ... Accepted合計 / ユーザー数 15 / 40

Slide 16

Slide 16 text

AtCoderの使用言語ランキング 16 / 40

Slide 17

Slide 17 text

AtCoderのつよい言語ランキング 17 / 40

Slide 18

Slide 18 text

Project Euler のランキング Statistics - Project Eulerに統計情報があるので取得 認証が必要なのでRSelenium パッケージでログイン rvestでスクレイピング 次の情報があるので可視化(件数が多いので上位50%のみ) ユーザー数...ユーザーがプロフィールで設定するもの 回答率...回答数/問題数が言語別に集計されたもの 18 / 40

Slide 19

Slide 19 text

Project Eulerの使用言語ランキング 19 / 40

Slide 20

Slide 20 text

つよい言語ランキング 20 / 40

Slide 21

Slide 21 text

やってみよう 21 / 40

Slide 22

Slide 22 text

Problem 1 -- Multiples of 3 and 5 3か5で割り切れる1000未満の自然数の合計は何か? PE版のfizzbuzzです。 22 / 40

Slide 23

Slide 23 text

PE001 回答例 23 / 40

Slide 24

Slide 24 text

素直に解く ans 0 for (i in seq_len(999)) { if (i 3 0 | i 5 0) { ans ans + i } } 良いと思います。 24 / 40

Slide 25

Slide 25 text

もっとFizzBuzz っぽく sum((x=1:999)[!(x 3&x 5)]) 書き方にこだわってみても良いでしょう。 25 / 40

Slide 26

Slide 26 text

もっと最近のR っぽく library(dplyr) data.frame(x = 1:999) %>% filter(x 3 0 | x 5 0) %>% summarise(answer = sum(x)) 好きなライブラリを使ったって良いんです。 26 / 40

Slide 27

Slide 27 text

Python が使いたいんじゃ print(sum(i for i in range(1000) if i % 3 0 or i % 5 0)) どうしてもPythonが良いというなら止めません。 27 / 40

Slide 28

Slide 28 text

あまり役に立たない知見が得られる問題が盛りだくさんです 28 / 40

Slide 29

Slide 29 text

Problem 92 Square digit chains 「各桁の値の2乗の合計を計算する」という操作を繰返します。 44 -> 32 -> 13 -> 10 -> 1 -> 1 85 -> 89 -> 145 -> 42 -> 20 -> 4 -> 16 -> 37 -> 58 -> 89 1つめの例では、1に到達し、2つめの例では89から始まるループに到達しています。実 は、操作を繰り返すとすべての自然数は1または89に到達します。 1千万以下の自然数のうち、89に到達する数はいくつあるでしょうか? 29 / 40

Slide 30

Slide 30 text

考え方 上限をN、ループ判定に必要な時間をMとして 程度の計算量が 必要です。 N = 1e7なので、Mの値次第では結構時間がかかります。 どうするか?(考えてみましょう) ヒント:ほぼ の解法があります O(N × M ) O(N ) 30 / 40

Slide 31

Slide 31 text

回答例 「2乗の和」の計算結果は、最大でも です すべての値について1回だけ処理をすれば、すべて486以下の値になりま す。 したがって486以下の整数について最終的に89になるのか?を把握してお き、配列などにメモっておけば高速に計算できます。 9 2 ∗ 6 = 486 31 / 40

Slide 32

Slide 32 text

Project Euler のここがすごい 日常生活で比較的使わない概念を知ることができます 32 / 40

Slide 33

Slide 33 text

Q. 何? 3 ⇈ 3 33 / 40

Slide 34

Slide 34 text

答: テトレーション cf. 大きな数が好きなら寿司 虚空編を読もう! 3 ⇈ 3 = 3 3 3 = 3 27 = 7, 625, 597, 484, 987 34 / 40

Slide 35

Slide 35 text

Problem 188 の下8桁を求めよ。 ヒント1: 桁だけでメモリが死ぬので直接計算してはいけません ヒント2: 冪乗演算子は右結合なので左から計算してはいけません # n 1777 for (i in 1:1855) n n^1777 mod 1e8 1777 ⇈ 1855 35 / 40

Slide 36

Slide 36 text

オイラーの定理 と を互いに素な正整数とします。このとき次の関係が成立します。 はオイラーの (トーシェント)関数というもので、 以下の自然数で と互いに素な自然数の個数を返します。 例) なら1と5が互いに素なので 。 とすると、 となってオイラーの定理が成り立つ。 a n a φ(n) mod n = 1 φ(n) φ n n n = 6 φ(6) = 2 a = 5 5 2 mod 6 = 1 36 / 40

Slide 37

Slide 37 text

で? 1777は素数なので、1e8と互いに素です。つまり次の関係が成り立ちます。 乗する度に下8桁が00000001に戻るということです。つま りこうです。 指数部分の剰余をとってから計算して良いということです。 1777 φ(10 8 ) mod 10 8 = 1 φ(10 8 ) = 4 × 10 7 1777 x mod 10 8 = 1777 x mod 4×10 7 mod 10 8 37 / 40

Slide 38

Slide 38 text

コードにするとこう solve function(a, b, m) { ans = 1 for (i in seq_len(b)) { if (i b) m = 1e8 ans = modpow(a, ans, m) } return(ans) } solve(1777, 1855, 4e7) ※冪乗の剰余を計算する関数がRには無いので適当に定義する必要がありま す。メンドイ!! 38 / 40

Slide 39

Slide 39 text

実は… ループは10回で良い で剰余とっても良い Pythonだと楽 x = 1 for i in range(10): x = pow(1777, x, 10 8) print(x) とかいろいろあって闇が奥が深いです。問題解いてからforum覗いてみるとよ いでしょう。 10 8 39 / 40

Slide 40

Slide 40 text

終 40 / 40