競プロ精選100プログラミング

競プロ精選100問

競プロ
元記事のスクリーンショットです。
この記事は約22分で読めます。

リンク -> 分野別 初中級者が解くべき過去問精選 100 問
競プロ精選100問を全部解きたいので、このページでタスク管理を行う
途中まで進んだ段階からこの記事を作成しはじめたため、とりあえず途中から開始する。
一通り終わったら、初めの方のものも順次更新したい。

  1. DP (Dynamic Programming: 動的計画法)
    1. 区間DP
      1. 46 ALDS_10_B – 連鎖行列積
      2. 47 JOI 2015 本選 2 – ケーキの切り分け 2
      3. 48 AOJ 1611 ダルマ落とし
    2. bitDP
      1. 49 DPL_2_A – 巡回セールスマン問題
      2. 50 Square869120Contest #1 G – Revenge of Traveling Salesman Problem
      3. 51 JOI 2014 予選 4 – 部活のスケジュール表
      4. 52 JOI 2017 予選 4 – ぬいぐるみの整理
    3. 動的計画法:その他
      1. 53 DPL_1_D – 最長増加部分列
      2. 54 AtCoder Beginner Contest 006 D – トランプ挿入ソート
      3. 55 AtCoder Beginner Contest 134 E – Sequence Decomposing
      4. このカテゴリの感想
  2. グラフ
    1. ダイクストラ法
      1. 56 GRL_1_A – 単一始点最短経路
      2. 57 JOI 2008 予選 6 – 船旅
      3. 58 JOI 2016 予選 5 – ゾンビ島
      4. 59 JOI 2014 予選 5 – タクシー
      5. このカテゴリの感想
    2. ワーシャル・フロイド法
      1. 60 GRL_1_C – 全点対間最短経路
      2. 61 AtCoder Beginner Contest 012 D – バスと避けられない運命
      3. 62 AtCoder Beginner Contest 079 D – Wall
      4. 63 AtCoder Beginner Contest 074 D – Restoring Road Network
      5. このカテゴリの感想
    3. 最小全域木
      1. 64 GRL_2_A – 最小全域木
      2. 65 JOI 2010 春合宿 – Finals
      3. 66 AOJ 1127 – Building a Space Station
      4. 67 AtCoder Beginner Contest 065 D – Built?
      5. このカテゴリの感想
  3. 整数
    1. 高速な素数判定法
      1. 68 NTL_1_A – 素因数分解
      2. 69 AtCoder Beginner Contest 084 D – 2017-like Number
      3. このカテゴリの感想
    2. 高速なべき乗計算
      1. 70 NTL_1_B – べき乗
      2. 71 Square869120Contest #1 E – 散歩
      3. このカテゴリの感想
    3. 逆元を使う問題
      1. 72 AtCoder Beginner Contest 034 C – 経路
      2. 73 AtCoder Beginner Contest 145 D – Knight
      3. 74 AtCoder Beginner Contest 021 D – 多重ループ
      4. 75 AtCoder Beginner Contest 149 F – Surrounded Nodes
      5. このカテゴリの感想
  4. 累積和
      1. 76 全国統一プログラミング王決定戦本戦 A – Abundant Resources
      2. 77 JOI 2010 本選 1 – 旅人
      3. 78 JOI 2011 本選 1 – 惑星探査
      4. 79 AtCoder Beginner Contest 106 D – AtCoder Express 2
      5. 80 GigaCode 2019 D – 家の建設
      6. 81 AtCoder Beginner Contest 014 C – AtColor 
      7. 82 AOJ 2013 – 大崎
      8. 83 JOI 2015 本選 1 – 鉄道運賃
      9. 84 JOI 2012 本選 4 – 釘
      10. このカテゴリの感想
  5. UnionFind
      1. 85 DSL_1_A – 互いに素な集合
      2. 86 AtCoder Beginner Contest 075 C – Bridge
      3. 87 AtCoder Beginner Contest 120 D – Decayed Bridge
      4. このカテゴリの感想
  6. その他のテクニック
    1. 圧縮
      1. 88 JOI 2008 本選 1 – 碁石ならべ
      2. 89 JOI 2013 本選 1 – 電飾
      3. このカテゴリの感想
    2. 初等幾何
      1. 90 Square869120Contest #5 B – Emblem
      2. 91 AtCoder Beginner Contest 144 D – Water Bottle
      3. このカテゴリの感想
  7. 実装問題
      1. 92 AOJ 1193 – 連鎖消滅パズル
      2. 93 Square869120Contest #3 B – 石落としゲーム
      3. 94 AOJ 1149 – ケーキカット
      4. このカテゴリの感想
  8. 数学的な問題
      1. 95 AtCoder Beginner Contest 149 B – Greedy Takahashi
      2. 96 AtCoder Beginner Contest 139 D – ModSum
      3. 97 AtCoder Beginner Contest 150 D – Semi Common Multiple
      4. 98 三井住友信託銀行プログラミングコンテスト2019 予選 E – Colorful Hats 2
      5. 99 DDCC2020 予選 D – Digit Sum Replace
      6. 100 Tenka1 Programmer Beginner Contest D – Crossing 
      7. このカテゴリの感想

DP (Dynamic Programming: 動的計画法)

区間DP

46 ALDS_10_B – 連鎖行列積

ポイント
  1. 区間幅
  2. 開始位置
  3. 区間内区切り

上記のポイントを基準に3重ループを行い、dpを更新する
初見、実装時は3を必要ないと考えてしまっていた。。

47 JOI 2015 本選 2 – ケーキの切り分け 2

ポイント
  1. メモ化再帰 x 区間DP

30分以上考えたが、実装方針が立たず投了。。
DP=forループという思い込みによって上記が思いつかなかった。
まだ、解説を読んだだけなのだが、実装も結構難しそう。。

48 AOJ 1611 ダルマ落とし

ポイント
  • 典型の区間DP(46と一緒)
  • 区間幅の最後に「だるまが全て打ち抜けた場合」のdp更新

区間DPのかなり典型的な問題だったのだが、慣れてないのもあって全然方針が立たなかった。
DPは本当に色々なパターンがあって難しい。
多少の反復練習が必要そう。。(精選100問はおそらく範囲が被らないように選択されているので、こういった面ではちょっと使いにくいかも)
苦手分野克服のための問題集などを探して解いたほうが良いか。。
解き直しをすればおそらく良いのだが、難しい問題は方針が立たないことが多いので、多少は答えを見るのは仕方が無い気もする。。

実装も個人的には結構難しかったので、コメントをできるだけ付けた解答のページを作成。(以下リンク)
詳細解説ページ

bitDP

49 DPL_2_A – 巡回セールスマン問題

ポイント
  • dfs(depth first search)でDP更新
  • グラフの頂点数が15と少ないので、状態をbit(2^15 = 32768)で管理できる

これも自力では解けなかった。。
dpテーブルの設計が個人的に本当に苦手。
また、dfsを工夫するのが難しすぎる。。少しの応用で解ける問題を解いて経験を積んだほうが良いのだろうか。。
答えをみれば実装が理解できるようになったのは進歩だと思うが、一から実装できる気がしない。。

こちらも実装が難しかったので、コメントをできるだけつけた個別解答ページを作成(以下リンク)
詳細解説ページ

50 Square869120Contest #1 G – Revenge of Traveling Salesman Problem

ポイント
  • 49のDP更新時に時間制限を追加
  • dpをpair<long long, long long>にすることで最短経路の数を保存

時間制限の追加はできたのだが、最短経路の保存は思いつかなかった。
最短経路保存の方はメモ化再帰の終了条件が良くないIのか実装しきれていないが、ポイントは上記なので、もう飛ばす。(メモ化再帰のデバッグだるすぎ)

51 JOI 2014 予選 4 – 部活のスケジュール表

ポイント
  • dp更新時に前状態と現状態の両方のbitを比較して更新を行う

シンプルな問題だったので、はじめ方針がうまく建てられなかったが実装していくうちに解くことができた。鍵の受け渡しをどのように考えるかがポイントで、上述のように状態を比較して両方来ている人がいるかどうかで判別し、いる場合のみ値をもらうように更新すれば良い。
こちらもコメントを付けてものを実装したので別記事にまとめた。

52 JOI 2017 予選 4 – ぬいぐるみの整理

ポイント
  • ぬいぐるみの順番のみ考えれば良い
  • その際にbitDPでN! -> 2^Nにうまく計算量を削減できることがあるので、これを利用する

1つ目のポイントは制約条件からしてすぐに気づいたのだが、2つ目のポイントは全く思いつかなかった。実装をみてもbit全探索してdpを更新していくことで、順列を調べていくというのを理解するまでにかなり時間がかかった。
これが利用できることを知っていれば方針は立てやすいが、実装は完成してものを修正しながら行わないと厳しそう。。

一応、コメントを大量に追記して自分で解釈しながら写経して、コードを作成したが、うまくコメントできているか自信はない。 -> 個別記事

動的計画法:その他

53 DPL_1_D – 最長増加部分列

ポイント
  • 長さkの最長部分列の最小値を持ち、更新していく
  • 更新する際は二分探索することで高速化(最長部分列の最小値はかならず昇順になるため、二分探索が有効)

ポイントにつきる。
アイデア一発という感じ。これを自力で思いつくのが難しいから有名問題なんだと思う。
個人的には添字をインデックスにしていないせいか、dp tableという感じがしないが、動的に計算を更新していく際のバッファという観点ではバリバリdp table何だと思う。
解説はこちらの記事が具体的でわかりやすかった。

54 AtCoder Beginner Contest 006 D – トランプ挿入ソート

ポイント
  • 最長増加部分列を使う

上記53を解いたすぐあとだったこともあったが、最長増加部分列を求めて、元の配列の大きさから引くことでACできてしまった。

55 AtCoder Beginner Contest 134 E – Sequence Decomposing

ポイント
  • 各色の最大値を管理するバッファを用意
  • 最長増加部分列と同じ考え方で、配列を順に見ていく際にどの色に所属させるべきかが一意に決まる。また、その判定に二分探索が使える
  • 新たな色を追加する際に一番小さい最大値になるので、push_frontが高速なstd::dequeなどを使用する

これも53, 54に続いて取り組んだおかげか、上記のおそらく正攻法の答え方にたどり着くまでが早かった。
添字で少し戸惑ったが、チャレンジ問題とされている割にはそこまで難しくなかった印象。
公式解説と少しはじめの考え方がちがったので、一応個別記事を作成。

このカテゴリの感想

「動的計画法:その他」というカテゴリ名の割には、最長増加部分列とその応用問題たちといった印象だった。
53は解けなかったが、それを理解したことで54、55を自力で解くことができて、カテゴリのまとめとしての理解につながったのはとても良かった。

グラフ

ダイクストラ法

56 GRL_1_A – 単一始点最短経路

ポイント
  • 典型問題。これを解けるような自己ライブラリを用意しておく

完全な典型問題なので、用意してあるダイクストラライブラリで実装。
ダイクストラは慣れてくるとpriority_queueの実装がシンプルで良い。

57 JOI 2008 予選 6 – 船旅

ポイント
  • 典型 + 逐次処理

典型のダイクストラを関数化してグラフを都度更新して、都度ダイクストラを実行してもC++なら計算時間は間に合う。56に比べてアルゴリズム的に新しい要素は無いように思う。

58 JOI 2016 予選 5 – ゾンビ島

ポイント
  • 幅優先/深さ優先 + ダイクストラ

重みつき作成するために通常のグラフ探索(距離の計算)が必要。 距離の計算結果とゾンビの位置、開始地点、終了地点で重みの場合分けを行う必要がある。(開始、終了時の判定をしないと、間違った結果になるので注意) 幅優先はかなり計算時間については適当だったが、C++なら実行制限が10sとゆるいので間に合う。(私は6180msだった。)

59 JOI 2014 予選 5 – タクシー

ポイント
  • 幅優先で距離計算 + ダイクストラ
  • 緩和部分を重みつき辺でなく、幅優先で事前計算しておいたものを使用

初めは重みつき辺を幅優先での距離探索をもとに作成すれば良いかと考えて実装したが、それだと同一の辺ができてしまう。(同一の辺ができると、マイナスの辺ができるのと同じ効果になるため、ダイクストラが使えない)

そこで、ダイクストラ自体の修正が必要と考えて、重み付きグラフでなく、到達可能かどうかを表す行列とコストの2つのバッファを用意して、これを用いて更新を行うことで実装したところ、こんかいも2308msと時間はかかっているが、制限がゆるい(10s)ためAC。

このカテゴリの感想

基本的に典型を修正していく形で実装していけるイメージ。

また、グラフアルゴリズムに関してはあまり計算時間は考慮しなくても、どの典型を用いるかをうまく選択すれば制限時間は通るように思われる。
(まだ、このカテゴリしか演習してないのではっきりとはいえないが。。)

ワーシャル・フロイド法

おそらく知ってないと厳しいアルゴリズムかと思う。この間ABCに類似問題が出題されていたが、知っていたおかげで大分楽ができた。

60 GRL_1_C – 全点対間最短経路

ポイント
  • 典型問題、DP

典型問題。これをライブラリとして整備したほうが良さそう。

61 AtCoder Beginner Contest 012 D – バスと避けられない運命

ポイント
  • 典型ワーシャル・フロイド
  • 無向グラフなことで両方向の辺を追加
  • 出力する際に最大値を求める

典型問題をひと工夫するだけで解ける。

62 AtCoder Beginner Contest 079 D – Wall

ポイント
  • グラフで考える
  • 典型ワーシャル・フロイド

使うアルゴリズムがわかっていると楽。

63 AtCoder Beginner Contest 074 D – Restoring Road Network

ポイント
  • ワーシャル・フロイドで全点対間最短路を求める
  • 求めた結果と辺を比較して、構造の存在を判定する

これは今までと違ってかなり難しくて、自力で解くことができなかった。
構造の存在判定が特に実装の先が見えなかったので、ワーシャル・フロイドでとりあえず最短路を求めるということもできなかった。
個人的に問題の分割というのが上手くできていない気がするので、意識したい。

このカテゴリの感想

ワーシャル・フロイドを使うということがわかれば、そこからの応用はそこまで難しくなかった印象。

最小全域木

これもクラスカル法を知らないと難しいと思う。

64 GRL_2_A – 最小全域木

ポイント
  • UnionFindを用いてクラスカル法を実装。

基本問題。クラスカル法自体は実装は重くないので、ライブラリとして持っておく必要はないかも?

65 JOI 2010 春合宿 – Finals

ポイント
  • クラスカル法を途中まで行えば良いことに気づく(もしくは最後のK本を除く)

最小全域木を求める際に最後のK本を除くことで問題の要求する答えになることに気づければ実装は典型問題を少し改修すれば良い。

名前が紛らわしいが「Finals」という名前の問題。

頂点IDが違うという実装ミスだったので、ほとんどテストケースが通ってしまっていてミスに気づくのに時間がかかった。

66 AOJ 1127 – Building a Space Station

ポイント
  • 入力データからグラフを作成
  • 典型クラスカル法

問題文英語だけです。ただ、今は翻訳ツールがあるので、deeplで全文変換したらほとんどの内容は理解できた。

問題自体は入力データをグラフに変換したらクラスカル法をそのまま適用するだけで解ける。

今回も、return文の位置を間違えて大分バグ探しに時間がかかってしまった。。

67 AtCoder Beginner Contest 065 D – Built?

ポイント
  • 辺の数を減らす工夫して入力データをグラフに変換
  • 典型クラスカル法

元記事のヒントに従って、制約条件がN<=2*10^5なので、N^2の辺を減らせるように工夫をすれば良い。
今回の問題ではx, yのそれぞれでソートして隣の頂点とのみ辺を結ぶようにすると、2*(N-1)個の辺だけ用意すればよく、それ以外同士の頂点同士の辺は最小全域木には不要な点となるのでこれで十分。
同一間の辺が2つできる可能性があるが、これはクラスカル法が最小のながさの辺から利用していき、それ以降の同じ頂点同士の辺は捨てるというアルゴリズムのため、問題ない。

このカテゴリの感想

ワーシャルフロイド同様アルゴリズムが強力のため、典型に落とし込みやすかった。

知ってるか知ってないかが大きいため、出題頻度は多くないかもしれない。

整数

高速な素数判定法

68 NTL_1_A – 素因数分解

ポイント
  • N <= 10^9なので、√Nまでで判定を行えばよい

for文を√Nまで行って、中でwhileを呼んで順に追加していけば良い。
素数だった場合に最後に自身を追加する点に注意。

69 AtCoder Beginner Contest 084 D – 2017-like Number

ポイント
  • エラトステネスの篩
  • 累積和

ポイントの通り。
実装方針はあってるはずだが、ACにならなかった。
何かWAになったのだが、よくわからん。テストケースはもっと簡単にDLできるようにしてほしい。
トライアンドエラーが全然できない。
バグ解決面倒なので、近い実装の人のコードをコピペしてAC。
本当、境界値とかでエラーにされるの嫌だがからサンプルケース多くしてほしい。

このカテゴリの感想

実装方針は割と単純だし、検索すれば参考になりそうな実装がたくさんある。

高速なべき乗計算

70 NTL_1_B – べき乗

ポイント
  • m^(2^0), m^(2^1), m^(2^2), …, m^(2^30)のリストを作成する
  • nを2進数と考えて2^iの桁が1のとき、リスト[i]を掛けて、答えを求める

1つ目のポイントの上限を見極めるのが少し難しいが、それ以外は単純。
(n<=10^9より2^30 = 2^(10+10+10) = 1024*1024*1024 ≒ 1000*1000*1000 = 10^9より30までで良い)
bit全探索などでシフト演算などを知っていると楽に実装できるが、知らないと少し面倒かも。

71 Square869120Contest #1 E – 散歩

ポイント
  • atcoderライブラリのmodintを使用する
  • 累積和

atcoderライブラリを使用するとただの累積和の問題。
絶対これで解くべきではないが、解けてしまうものはしょうがない。

このカテゴリの感想

整数系の問題はatcoderライブラリが使用できればかなり楽できるのでは?
フェルマーの小定理など理解できていないので、どこかでまとめて勉強したくはあるのだが。。

逆元を使う問題

72 AtCoder Beginner Contest 034 C – 経路

ポイント
  • nCrを求める(分母と分子の掛けていく順番を工夫すると、ずっと整数のまま計算できる)

atcoderライブラリのmodintを使用すれば上記の工夫だけで実装できる。
atcoderライブラリが無くとも自己ライブラリを準備していれば簡単に実装できるのでライブラリは正義。

73 AtCoder Beginner Contest 145 D – Knight

ポイント
  • ベクトル
  • nCr

ベクトルの考え方を使うと、組み合わせの計算に帰着できる。

74 AtCoder Beginner Contest 021 D – 多重ループ

ポイント
  • nCr

これもatcoderライブラリを使ってnCrするだけ。

75 AtCoder Beginner Contest 149 F – Surrounded Nodes

ポイント
  • 頂点ごとに部分木S内の白頂点になるかどうかを考える
  • 対象の頂点につながる部分木のリストのうち、黒が含まれるものが二個以上あれば良い
  • 余事象を考えて、対象の頂点につながる部分木のリストのうち、黒が含まれるものが1つor0の場合の通り数を考える
  • 部分木のリストのサイズがわかれば計算可能(それをDFS中に行うことができる)

いきなりレベルあがりすぎ。
解説記事みてもわかんなかった。動画があってようやくわかったがまだあやふや。。

これは個人的にはDFSの問題。(このカテゴリの問題がatcoderライブラリのmodintライブラリでほとんど解決されてしまっているというのもあるが。)

DFSとDPは奥が深いと感じる。
簡単な問題をたくさん解いて慣れたい。(毎回新しい問題だと発想力的に厳しいものがある。。)

このカテゴリの感想

おそらくこのカテゴリ自体はatcoderライブラリがあればかなり楽。
ただ、最後のだけ考察が難しい。DFSの問題。

累積和

76 全国統一プログラミング王決定戦本戦 A – Abundant Resources

ポイント
  • 基本とあるが、累積和は丁寧に実装しないとすぐバグる

考察自体はすごい簡単だが、添字が多く丁寧に実装しないとバグる。
for文の境界値とか大嫌いなので緩くしてほしい。。

77 JOI 2010 本選 1 – 旅人

ポイント
  • 累積和

76より素直。バグらせずに実装できた。

78 JOI 2011 本選 1 – 惑星探査

ポイント
  • 二次元累積和(4つの領域を足し引きする (tot[xmax][ymax] – tot[xmax][ymin-1] – tot[xmin-1][ymax] + tot[xmin-1][ymin-1])
  • 実装はちょっと面倒。

相当、愚直に実装したこともあるが、100行近くプログラムが必要だった。
累積和のリストは引くことを考えて、N+1のサイズにしたほうが良さそう。(ちょっと添字考えるのが嫌だが。)

79 AtCoder Beginner Contest 106 D – AtCoder Express 2

ポイント
  • 半分累積和(LかRのどちらかに対して累積和を行う)
  • Nが小さいので二次元バッファを余裕で持つことができる、NQの計算量が許される

半分累積和でバッファを持つことで、各クエリー対してO(N)で解答が可能だが、頑張れば各クエリーに対してO(1)で回答することも可能だと思われる。

初見では解けなかったが、理解していれば解くことのできる良い問題だと思う。

80 GigaCode 2019 D – 家の建設

ポイント
  • 二次元累積和
  • 慣れないうちは累積結果を確認

二次元累積和を作成すれば、H*H*W*Wの全探索をしてもH,Wが小さいので計算時間は間に合う。
累積和の作成で境界値付近の値が怪しくバグらせてしまったので、慣れないうちは出力して結果を確認したほうが良いと思われる。

81 AtCoder Beginner Contest 014 C – AtColor 

ポイント
  • 1次元いもす法

1次元いもす法をそのまま適用する問題。また境界値でバグらせてしまったので気をつける。

82 AOJ 2013 – 大崎

ポイント
  • 1次元いもす法
  • 円環なので、着時刻の設定を少し改良する

前設定が長い問題。(たぶん最初は読まなくても良い)
実装上は時刻(hh:mm:ss)をどうパースするかで少し悩む。
(今回はsubstrとstoiでパース)
81のちょっとの改良で実装できたので、いもす法は流用しやすいかも。

83 JOI 2015 本選 1 – 鉄道運賃

ポイント
  • 1次元いもす法
  • intじゃ足りないのでlong longにする

今回もいもす法だが、足すインデックス、引くインデックスに注意して行う。
累積和はやはり出力しておいたほうが無難。
インデックスが嫌な問題は簡単な例をやってみて上手く行くか試すのが良いかもしれない。

84 JOI 2012 本選 4 – 釘

ポイント
  • 二次元いもす法
  • 横、縦、ななめで累積和
  • 上記のために6箇所更新

このカテゴリのボス。圧倒的に難しい。

上記の2ポイント目まではわかったが、更新位置を自力で求めることはできなかった。

また、ななめの累積和のときにうまくインデックスを設定しないとはまることがあるので注意。
(プリントでバッグを30分くらいやってようやっとインデックスがずれていたことに気づいた。)

このカテゴリの感想

結構応用問題は難しい印象。

問題数が多かったので演習にはなったと思う。

また、累積和を求める際のインデックス処理が厄介なので、累積和は簡単なケースで出力するなどして確認しながら実装したほうが良さそう。

UnionFind

85 DSL_1_A – 互いに素な集合

ポイント
  • UnionFind典型問題

典型問題。unionFindを使って各クエリを処理するだけ。

86 AtCoder Beginner Contest 075 C – Bridge

ポイント
  • N, M<=50と小さい
  • 小さいので各辺が橋であるか調べるために毎回unionFindを作成しても構わない。
  • unionFindのサイズがNであれば、連結。小さければ非連結と判定。

制約が緩いので、1つの辺だけを除いたunionFindを作成して、サイズを調べることで連結かどうかがわかる。

これを愚直に実装してもO(M^2)の計算量で実行できる。

87 AtCoder Beginner Contest 120 D – Decayed Bridge

ポイント
  • 壊すのでなくつないでいくと考えるとUnionFindが使える
  • つなぐ際にuf.size(a[i]) * uf.size(b[i])だけつながれることになる。(a[i]とb[i]が同じグループでない場合)
  • 上記の結果を全通り数(N*(N-1)/2)から引いていくことで求める結果となる
  • N<=10^5よりN^2はlong longが必要

2つ目のポイントが特に重要。
ちょうど、unionFindの関数であるissame, size, uniteを全て使用しており、unionFindの練習にもってこいという感じの問題。

このカテゴリの感想

UnionFindは強力な割には実装も単純で使いやすいので、覚えているだけで大分得するアルゴリズムだと感じた。
有名なアルゴリズムの書籍でも独立した章で紹介されていて、重要視されているのも納得。

その他のテクニック

圧縮

88 JOI 2008 本選 1 – 碁石ならべ

ポイント
  • ランレングス圧縮風にデータを管理する
  • 実装はvector<pair<bool, int>>で実装できた

圧縮するというアルゴリズムでは無いと思うが、ランレングス圧縮風にデータを持つことで計算量を減らすことができる。(愚直に実装するとN^2となり10^10オーダーになる)

89 JOI 2013 本選 1 – 電飾

ポイント
  • 交互列を圧縮する

愚直に解こうとするとなかなかポイントに気づきにくい問題。交互列を圧縮すると、一瞬で解答方法がわかる。

このカテゴリの感想

89のような問題はひらめきのような要素が必要(問題文から推測できるのかもしれないが)なので、似たような問題に対しては色々と圧縮方法を試してみるのが大事だと思った。

初等幾何

90 Square869120Contest #5 B – Emblem

ポイント
  • 円の性質
  • N^2が許される

最小の最大化ということで二分探索かと一瞬かと思ったが、実は探索は不要で、一意に求めることができる。
決まってない円同士はちょうど同じ半径にしたときに最小値が最大化し、それで決まっているNの円とぶつからなければそれが答え。ぶつかるなら、ぶつからないようにした値が答えになる。

91 AtCoder Beginner Contest 144 D – Water Bottle

ポイント
  • 半分以上水がはいるかどうかで場合分け
  • それぞれの場合で三角関数を用いて体積を計算
  • atanを用いてラジアン角度を求めて、180/PIをかけて度数表示にして出力

2パターンの体積を三角関数を用いて計算する。

このカテゴリの感想

紙で計算して式を実装するだけなので、かなり楽。
実装も短く書けるのでデバッグもおそらく容易だと思う。

実装問題

92 AOJ 1193 – 連鎖消滅パズル

ポイント
  • うまく途中状態を確かめながら実装する
  • 3個以上の連続判定は全部で6通りなのでベタ書きでも良いかも。
  • おとすときにインデックスが大きい方にずらさなければいけないので、その実装箇所が結構ややこしい。

実装問題とあるとおり、場合分けやインデックス処理などいちいち面倒な問題。
ロジックはシンプルなので、途中状態を適切に確認しながら実装すれば時間があれば解ける。

93 Square869120Contest #3 B – 石落としゲーム

パス。

ほとんど92と同じだが、最初に1つ選んで消す処理が増えていたり、スコアの計算方法が少し実際のゲームっぽくなっている。
92のコピペでほとんど解けるのであれば解いても良かったが、上記の1つ選んで消す処理とか面倒そうなので、これはパス。

94 AOJ 1149 – ケーキカット

ポイント
  • 適切に関数化する
  • erase, push_backでケーキを切っていく
  • ケーキの情報は面積でなく幅と高さ(w,d)で持つ

適切に関数化して見通しを良くして実装するのが重要。
コードは100行まで行かないで書けたので、92,93に比べればちょっと楽。

このカテゴリの感想

適切に関数化するのと、適切なタイミングで状態を確認するのが大事だと感じた。
実装が重い問題は各処理は単純だが直列に並ぶ処理が多いような印象なので、それぞれの処理を確かめるようにしながら実装すればバグりにくいと思う。

数学的な問題

95 AtCoder Beginner Contest 149 B – Greedy Takahashi

ポイント
  • 貪欲法の基礎

貪欲法の基礎の基礎と行った感じ。

96 AtCoder Beginner Contest 139 D – ModSum

ポイント
  • 一意に求めることができる
  • intじゃ足りないのでlong longを使う
  • 証明は難しいが計算量から逆算できてしまう。。

最大値を数学的に一意に求めることができるので、それを使うだけ。
めっちゃ短く書ける。

97 AtCoder Beginner Contest 150 D – Semi Common Multiple

ポイント
  • gcd(有名な再帰関数)
  • 最小公倍数で割る
  • 素因数分解した際に2の数が全てのaiで同じである必要がある

最小公倍数で割るという発想にはすぐたどり着いたが、その後丁寧な実装が必要。

割るときに1をたして割ったり、素因数分解した際の2の数が全てのaiで一緒である必要があるなどと細かい部分を注意しながら丁寧に実装する必要がある。
別々に上記のポイントに気づいてたのだが、全体として両方を実装に上手く組み込むことができなかった。
ちょっと難しい。

98 三井住友信託銀行プログラミングコンテスト2019 予選 E – Colorful Hats 2

ポイント
  • O(N)で解ける
  • 各処理で考えられる色の数を掛けていく
  • 0の場合は最初の0は3通りでそのあと出現するごとに2,1を掛ける
  • 0でない場合はその前までに出たその数より一つ少ない数の出現回数と自分自身の出現回数の差が通り数になるので、それを掛ける

2時間くらいかかってしまったが、解くことができた。
はじめは夜に解いていたのだが、この手の問題は特に朝のほうが解きやすいと思う。

N<=10^5なので、O(NlogN)のアルゴリズムが必要なのかと思ったが、そうではなかった。
こういう引っ掛けはあるのかもしれないので、Nの大きさでの判断に依存しすぎないほうが良いと思った。

99 DDCC2020 予選 D – Digit Sum Replace

ポイント
  • 桁の選び方には関係ない
  • 各桁の合計値(<= 9*10^15)はlong longの範囲に収まる
  • 毎回の操作で桁数が減らない場合は合計値がちょうど「9」減ることに気づく
  • 桁数が減る場合は合計値は変わらない

ポイントに気づけば実装はとても簡単。
実装面で言うと、2のポイントの考察に少し時間がかかってしまったが、long longは10^18までは大丈夫。

99問目にふさわしい?

100 Tenka1 Programmer Beginner Contest D – Crossing 

ポイント
  • 答えは一意に求めることができる
  • YesになるのはN = n * (n +1) / 2を満たすnだけ (制約1より)
  • n+1行n列になるので、左上を核にして、外側の殻をかぶせるように答えを求めることができる

方法を思いつくのに1時間、実装に30分位かかったが初見でACできた。
N=10まで答えがあるか確認することで実装方針が建てられた(N=6の答えを求めるのに大分手間取ったが。。)

公式解説の実装方法(階段状に数を並べる)は少し違ったが、答えは同じだった。

こういう問題は時間をかけて、具体例を求めていくと方針が見つかることが多いというのは大事かもしれない。

このカテゴリの感想

具体例を求めるのは大事。
実装に比べて考察が重いので、考察に時間がかかっても焦らないようにしたい。

コメント

タイトルとURLをコピーしました