Shinjuku.ts#1発表資料
Red Coder が TypeScript で競技プログラミングに挑戦して挫折した話 浦上 真之 2022.11.15 @Shinjuku.ts
View Slide
自己紹介● 浦上 真之(Masayuki Urakami) ○ Twitter: @tempura_cpp ● ソフトウェアエンジニア@フォルシア株式会社 ○ Webアプリケーション開発(TypeScript, Node.js, React, Next.js,PostgreSQL など) ● (元)競技プログラマ ○ AtCoder で最高レート 2865 を達成(上位約0.3%) 2あとでいい感じの画像に置き換える
競技プログラミング● 複数の課題が与えられて、それを解くプログラムを作成する ○ 試験時間内に正解した問題数や解答時間等で順位が決定する ○ 「複雑な処理を正しく記述する」「計算時間のかかる処理を、数学的/情報科学的に効率よく処理する」能力などを競う ● AtCoder ○ 国内最大の競技プログラミングコンテストサイト ○ 様々な言語が使用可能 ■ C, C++, Python, Java, Ruby, Rust, Haskell, … ■ JavaScript(Node 12.16.1), TypeScript(3.8) も! 3
過去に最高レート2865を達成した競技プログラマが業務で常用しているTypeScriptで挑戦すればどんな問題でも簡単に解ける説4
問題① (Atcoder Beginner Contest 277 B問題)問題概要2 文字の文字列がN個与えられるので以下の3つの条件をすべてみたすか (≒トランプの手札を表す文字列として適切か)判定せよ。 ● それぞれ文字列の1文字目は H, D, C, S のいずれかである ● それぞれ文字列の2文字目は A, 2, 3, …, 9, T, J, Q, K のいずれかである ● 全ての文字列は相異なる 5
解答例①6
問題② (競プロ典型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
解答例②(不正解)8
何がダメ?● 整数を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
ならば BigInt だ!10
TLE(実行時間制限超過)11
TLE(実行時間制限超過)12
過去に最高レート2865を達成した競技プログラマが業務で常用しているTypeScriptで挑戦すればどんな問題でも簡単に解ける説13
立証ならず14
ご清聴ありがとうございました15
諦めない● 結局 ○ number 型同士の計算のまま ○ 計算過程で一度も2^53-1を上回ることなく ○ x * y % p (x, y, p は 10^9 以下の正の整数)を計算 できればいいということ ● やってやろうじゃないか! 16
式変形①● 各数値は 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
式変形②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
式変形②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
式変形②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
こんな関数を定義して21
これでどうだ!22
AC(正解)23
過去に最高レート2865を達成した競技プログラマが業務で常用しているTypeScriptで挑戦すればどんな問題でも簡単に解ける説24
立証ならずが工夫次第で頑張れることもある25
EOF