Slide 1

Slide 1 text

Red Coder が TypeScript で競技プログラミン グに挑戦して挫折した話
 浦上 真之
 2022.11.15 @Shinjuku.ts
 


Slide 2

Slide 2 text

自己紹介 ● 浦上 真之(Masayuki Urakami) 
 ○ Twitter: @tempura_cpp 
 ● ソフトウェアエンジニア@フォルシア株式会社
 ○ Webアプリケーション開発(TypeScript, Node.js, React, Next.js, PostgreSQL など)
 ● (元)競技プログラマ
 ○ AtCoder で最高レート 2865 を達成(上位約0.3%)
 2 あとでいい感じの 画像に置き換える


Slide 3

Slide 3 text

競技プログラミング ● 複数の課題が与えられて、それを解くプログラムを作成する
 ○ 試験時間内に正解した問題数や解答時間等で順位が決定する
 ○ 「複雑な処理を正しく記述する」「計算時間のかかる処理を、数学的/情報科学的に効率よく 処理する」能力などを競う
 ● AtCoder
 ○ 国内最大の競技プログラミングコンテストサイト
 ○ 様々な言語が使用可能
 ■ C, C++, Python, Java, Ruby, Rust, Haskell, …
 ■ JavaScript(Node 12.16.1), TypeScript(3.8) も!
 3

Slide 4

Slide 4 text

過去に最高レート2865を達成した競技プログラマが 業務で常用しているTypeScriptで挑戦すれば どんな問題でも簡単に解ける説 4

Slide 5

Slide 5 text

問題① (Atcoder Beginner Contest 277 B問題) 問題概要 2 文字の文字列がN個与えられるので以下の3つの条件をすべてみたすか
 (≒トランプの手札を表す文字列として適切か)判定せよ。
 ● それぞれ文字列の1文字目は H, D, C, S のいずれかである
 ● それぞれ文字列の2文字目は A, 2, 3, …, 9, T, J, Q, K のいずれかである
 ● 全ての文字列は相異なる
 5

Slide 6

Slide 6 text

解答例① 6

Slide 7

Slide 7 text

問題② (競プロ典型90問 055) 問題概要
 N 個の整数 A1, A2, ⋯, AN と整数 P, Qが与えられる。
 この中から 5 個を選ぶ方法のうち、これら 5 個の整数の積を P で割ると Q 余るような
 ものが何通りあるか求めよ。
 制約
 ● 5 <= N <= 100
 ● 0 <= Ai <= 10^9
 ● 0 <= Q < P <= 10^9
 実行制限時間
 5 秒
 7

Slide 8

Slide 8 text

解答例②(不正解) 8

Slide 9

Slide 9 text

何がダメ? ● 整数を5個掛け算すると、最大で(10^9)^5 = 10^45 
 ● JavaScript の MAX_SAFE_INTEGER(= 2^53 - 1) を大きく上回っているので整数を正確に表 現できないため間違った答えになってしまう 
 ● a[i1] * a[i2] % p * a[i3] % p * a[i4] % p * a[i5] % p のように毎回 
 余りを取れば最大値を 10^18 程度に抑えられるがそれでも 2^53 - 1 を上回ってしまう 
 ○ 64bit 整数型を扱える言語(C++, Java, Rust など)はこの方法で正解することが
 できる(問題の想定解もこの方法)
 9

Slide 10

Slide 10 text

ならば BigInt だ! 10

Slide 11

Slide 11 text

TLE(実行時間制限超過) 11

Slide 12

Slide 12 text

TLE(実行時間制限超過) 12

Slide 13

Slide 13 text

過去に最高レート2865を達成した競技プログラマが 業務で常用しているTypeScriptで挑戦すれば どんな問題でも簡単に解ける説 13

Slide 14

Slide 14 text

立証ならず 14

Slide 15

Slide 15 text

ご清聴ありがとうございました 15

Slide 16

Slide 16 text

諦めない ● 結局
 ○ number 型同士の計算のまま
 ○ 計算過程で一度も2^53-1を上回ることなく 
 ○ x * y % p (x, y, p は 10^9 以下の正の整数)を計算 
   できればいいということ
 
 ● やってやろうじゃないか!
 16

Slide 17

Slide 17 text

式変形① ● 各数値は 10^9 < 2^30 なので高々30bit 
 ● xを32bit整数型で表したときの上位12bitをa, 下位20bitをb として 
 x = a * 2^20 + b (a<2^10, b< 2^20) 
 と表す
 ● 同様に
 y = c * 2^20 + d (c<2^10, d< 2^20) 
 と表す
 17

Slide 18

Slide 18 text

式変形② x * y % p = (a * 2^20 + b) * (c * 2^20 + d) % p 
      = { a * c * (2^40) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
      = {a * c * (2^40 % p) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
 
 18

Slide 19

Slide 19 text

式変形② x * y % p = (a * 2^20 + b) * (c * 2^20 + d) % p 
      = { a * c * (2^40) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
      = {a * c * (2^40 % p) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
 
 ● a * c * (2^40 % p) < 2^10 * 2^10 * 2^30 = 2^50 
 ● a * 2^20 * d < 2^10 * 2^20 * 2*20 = 2^50 
 ● b * (c * 2^20 + d) < 2^20 * 2^30 = 2^50 
 
 19

Slide 20

Slide 20 text

式変形② x * y % p = (a * 2^20 + b) * (c * 2^20 + d) % p 
      = { a * c * (2^40) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
      = {a * c * (2^40 % p) + a * 2^20 * d + b * (c * 2^20 + d) } % p 
 
 ● a * c * (2^40 % p) < 2^10 * 2^10 * 2^30 = 2^50 
 ● a * 2^20 * d < 2^10 * 2^20 * 2*20 = 2^50 
 ● b * (c * 2^20 + d) < 2^20 * 2^30 = 2^50 
 
 できたぁぁ!!!!!!!!
 20

Slide 21

Slide 21 text

こんな関数を定義して 21

Slide 22

Slide 22 text

これでどうだ! 22

Slide 23

Slide 23 text

AC(正解) 23

Slide 24

Slide 24 text

過去に最高レート2865を達成した競技プログラマが 業務で常用しているTypeScriptで挑戦すれば どんな問題でも簡単に解ける説 24

Slide 25

Slide 25 text

立証ならず が 工夫次第で頑張れることもある 25

Slide 26

Slide 26 text

EOF