2022年1月31日月曜日

AtCoder Beginner Contest 224

 Gまで七完。二桁順位は嬉しい。

コンテスト後のツイート


H - Security Camera 2

 解説放送を見てAC。

 ちゃんと理解はできていないけれど、双対を取ると簡単な問題に帰着される場合があることは分かった。

 今回は、

・フローを使いそう→だけどそのままの問題だと上手くいかない→双対を取ってみよう

 くらいな感じで良いのかな。
 双対問題が何になるかを考えるところは難しい。けれど、コストと容量が、最大と最小が入れ替わるといったあたりを考えて、あとはsampleが合うようにごちゃごちゃやる……くらいの気持ちで良いか。

 ちゃんと立式して、正確に双対問題を記述できる力もあれば良いのだろうけど、コンテスト中にやるのは厳しそう。資料とか見ながら時間をかければ、自力でやることはできそうな気もするし(本当?)。

2022年1月30日日曜日

エクサウィザーズプログラミングコンテスト2021(AtCoder Beginner Contest 222)

 Eまで五完。


F - Expensive Expense

 解説放送を見て、頂点を拡張して直径を使いAC。普通の木で直径を使うことはよくあるけど、重み付きの木で直径を使えるというのはちゃんと認識していなかった。
 全方位木DPのライブラリ化もしないとね……。

G - 222

 解説AC。
 解説を読んでも難しく感じた(とはいえ、なんとか式は追えたのでそこまで難しくはない)けど、「ちゃんと式変形しよう」というしかなさそう。整数問題の式変形に慣れるのが大事なのかな。

H - Beautiful Binary Tree

 解説放送を見てAC。(後半の証明はまだ見ていません)

・漸化式を立てる
・母関数を調べてみる
・ラグランジュの反転公式を適用すると良さそう

 という流れ。
 どのパートも難しいけど、「ラグランジュの反転公式」というものがあり、$A(x)=x*f(x)$($f$は$A$の式)みたいな形のとき、それを使うと良いことがあるかも? くらいは覚えておくと良いか。
 

2022年1月29日土曜日

Codeforces Round #768 (Div. 1)

 Dまで四完して、久しぶりにレートが2300を超えた。

コンテスト後のツイート

 Eはポリアの数え上げ定理らしいが、この定理についての理解が浅いので解く(解説を追う)のは厳しいなぁ……。解くべきではあるのだけど。

yukicoder contest 329

 Cまで三完。D解けなかったのは多いに反省。

コンテスト後のツイート

No.1826 Fruits Collecting

 解説AC。
 いわゆる「45度回転」の問題。
 二次元にプロットしたとき、斜め右下と斜め左下の範囲から最大値を取ってくる……までは分かったのに、45度回転が出てこないのはダメ。
 「45度回転」というと、マンハッタン距離のときに使う印象が強いけど、こういうときにも使えるのですね。

No.1827 最長部分スーパーリッチ門松列列

 これは自力でAC。

 xが境目だとすると、xより大きいものを1、xより小さいものを0としたとき、値が変化する部分列の長さが答え。
 境目が1大きくなったとき、変化するのは一要素だけ。

 つまり、最初は境目をx=0としておき、x+=1としたとき、1から0に変化するものがどれかを見る。そうやって差分計算をしていけばOK。

2022年1月27日木曜日

AtCoder Beginner Contest 236

 Fまで六完。

コンテスト後のツイート

G - Good Vertices

 解説放送を見てAC。

 まず「頂点の移動を隣接行列で表そう」とすら全く考えなかった。難しいのはその後なのに……。
 その後のパートが難しいのだけど、行列累乗しようという気持ちになっていないためその難しさがよく分からず。

Ex - Distinct Multiples

 解説放送を見てAC。

 辺に関して包除原理を行う→$3^N$のDPに帰着という流れ。
 難しいが、各ステップは滅茶苦茶難しいわけではないので、素早く解く人がいるのも分かる。

 $3^N$のDPの実装に戸惑ったのは反省。
 同じものをダブルカウントしないため、「ある頂点を含むものだけ考える」などしなくてはいけない。(自分は、$p<p$ xor $i$と、「一方がそれを除いたものより小さい」と書いた)
 書いたことがあったのにここで戸惑ったのは反省。

2022年1月23日日曜日

Codeforces Round #767 (Div. 1)

 D1まで四完。

コンテスト後のツイート

D2. Game on Sum (Hard Version)

 D1は実験エスパーといえばそうなんだけど、正しい漸化式を使って実験していた(漸化式を導いていたのに、それを使って二分探索で答えを探していた)。エスパーといいつつほぼ正しい解法通りやっていたので、まあ。

 D2は、それを高速化する。
 パスカルの三角形っぽいのだから、経路数に帰着できるのでは? と考えれば良かった。
 
        0
      0   1
    0   1   4
  0   1   5   12
0   1   6   17   32

 という三角形の各数字は、右端の数字たちが何回か足されることによって成り立っている。
 三行目の右端の数字は4だけど、一つ上の数字との差分3がここに書いてあったと考える。
 このとき、五行目の三つ目の数字「6」は、この3と、その上の1からの和で成り立っている。二行目の「1」からの経路は3C1=3。なので、この和が6と求められる。

2022年1月19日水曜日

HHKB プログラミングコンテスト 2022(AtCoder Beginner Contest 235)

 Eまで五完。

コンテスト後のツイート

F - Variety of Digits

 桁DP。
 コンテスト中は下の桁からやろうとしたが、上の桁からの桁DP(そこまで一致しているかのflagを持つやつ)を書いたらいけた。
 下の桁からでもできるかもしれないけど、そうやろうとして混乱するくらいなら上の桁からやった方が良いかね。


G - Gardens

 解説AC。
 包除原理+二項係数の和の高速化。
 どちらも無理な発想という感じはしないので、ちゃんと時間をかけたら解けたかもしれない。ただ、コンテスト中は包除原理を全然考えなかったので、厳しかったかも。

Ex - Painting Weighted Graph

 解説放送を聞いてAC。
 最小全域木+二乗の木DP(の亜種)。

 これも、まあまあ自然な発想を重ねれば解ける問題という気はした。最初の問題の見た目からは、二乗の木に行きつくとは想像し辛いので難しい。
 ただ、DPの遷移式を立てるところは難しい。これで良いはず……と思ってからWAをたくさん出してしまった。

2022年1月16日日曜日

Codeforces Round #766 (Div. 2)

 Eまで五完。

コンテスト後のツイート

 Fはやらなそうなので、これだけで投稿。

2022年1月15日土曜日

Codeforces Round #765 (Div. 2)

 Cまで三完でした。Dは難しかった。


D. Binary Spiders

 いくつかの解法ツイートを見てAC。

 まず、上位bitから考えていき、kのx bit目が0か1かで場合分けする。
 0の場合は、「x bitが0の集合」「x bitが1の集合」という二つの問題に分割される。

 kのx bit目が1の場合が問題。
 x bit目が0のものと1のもの高々二つしか取れないが、全探索すると二乗になってしまう。

 そこで、x bitが0のものを全探索することにし、もう片方はTrie木を使って整理する。x bit目が0の要素aに対して、できるだけa^uが大きくなるようなuをTrie木を利用して探していく。そのxorがk以上ならばそれを採用、そういう組が一つもなければ、何か一要素を適当に採用する。

 Trie木を使い慣れていないこともあり、この解法は自力ではなかなか思いつけなかった気がする。自分のライブラリのTrie木が意外と使いやすかったのには驚いた。

yukicoder contest 327

  Eまで五完。F思いつかなかったのは良くない。


No.1811 EQUIV Ten

 解説AC。
 2進法で表して考えるという発想がなかった。割る数字が$2^k$と16なのだから自然な発想なのに……。
 その言い換えができれば、後の考え方は自然ですね。

No.1812 Uribo Road

 ダイクストラで前計算をし、ダイクストラ+bit DP。
 これはFより簡単ですね。こっちを先に見ていれば解けていたと思う。

No.1813 Magical Stones

 解説AC。
 SCCを使うだろうとは思ったが、それ以外の処理が分からなかった。

 入次数と出次数だけ見れば良いのですね。そこさえケアすれば強連結にできる。言われてみれば確かに。

2022年1月13日木曜日

AtCoder Beginner Contest 217

 Eまで五完でした。


F - Make Pair

 いかにも区間DPの問題だが、遷移が分からなかった。

 コンテスト後、落ち着いて考えると、DP[x][y]について、「最後にlとr(x<=l<r<=y)を使ったとしたら……」と考えることで遷移できることに気付いた。しかし、これだと答えは合うが四乗になってTLE。

 解説を見ると、x(DP[x][y]の左端)とペアになるものを探索することで遷移式が書ける、とあった。
 解説を読めば確かに、という感じなのだけど、この遷移でいけるのは結構気付きにくい気がする。区間DPで三乗でいけるはず、というところから思いつく感じかなぁ。

 

G - Groups

 コンテスト後、包除原理の方針で自力AC。
 コンテスト中考えていた方針で大体合っていて、冷静になればどこが間違っていたか気付けた。これはコンテスト中に通せるべきだった。

 ……が、Fで時間を取られて冷静さを失っていたことが影響したと思う。この問題を反省するよりFを反省すべきか。

H - Snuketoon

 解説放送や、maspyさんのslope trickに関する解説を読んでAC。

 「プレイヤーが動く」と考えるのではなく、DPを考えて、そのDPテーブルの図形について考える(動かす)というのはちょっとした発想の転換か。

 ただ、maspyさんが挙げている問題例を見ると、slope trickの問題ではこの見方は常套手段のよう。身に着けておきたい。

2022年1月12日水曜日

Codeforces Round #764 (Div. 3)

 pretest全完。全部通ると良いなぁ。→通っていました。

コンテスト後のツイート

2022年1月10日月曜日

トヨタシステムズプログラミングコンテスト2021(AtCoder Beginner Contest 228)

 AB二完という過去最低(灰パフォ相当は初めて!)の成績。


C - Final Day

 今までの合計点でソートして大きい方からK番目の値が基準になる。今までの点数+300がそれ以上かで判定。
 基準値を得るところで、ソートしたものではなく元の数列を見ていたためWA。そして、コンテストが終わるまでそれに気付けなかった。多分、質問に「"in the top K" means……」という文章があったため、「上位 K 位以内」の解釈がおかしいのかな……と疑っていたためだと思う。
 自分のコードも何度も見直したつもりだったが、誤読の可能性の方が高いと思っていたため見直しが浅くなっていたのかもしれない。

D - Linear Probing

 最初、左右を管理するリストを付けばできると思ったが、それだと1ケースTLE。(1, x)というクエリが繰り返しくるとき、左右の管理だけでは難しい。
 なので、Union-findを使えば良いと思ったが、上手い実装を思い付けなかった。

 冷静になれば、xとx+1をUnioinするとき、x+1側の最大値を得る配列を用意しておけば簡単に実装できる。

E - Integer Sequence Fair

 問題を開いてすぐ、この記事を見に行った。
 これで良いのだが、pow(a, b)がa=b=0のとき1になるというのに注意せねばならなかった。このコーナーケースは盲点でした。
 今回、コンテスト中冷静じゃなかったけど、Dまで普通に解けていたとしても気付いたかどうか……。

F - Stamp Game

 解説放送を見てAC。
 実装の簡単さのため、縦横ともSparse tableを使った。

 二次元Sparse tableの復習もしようと思ったけど、横向きにSparse tableを作っておき、縦方向へは、それぞれのnodeについてSparse tableを構成、というので良いのかな。(そう考えればそんなに混乱しなそう?)

G - Digits on Grid

 解説放送を見てAC。
 DPのキーとして何を使うかが重要だが、「同じ数字を取りうるものの集合」を使えば良いということですね。

 ところで、この問題が類題な気がする。前に解説を読んでも理解できなかったのだけど、今なら解けるはず?

 ACできたらその旨を追記します。 → ACできました! なお、行列累乗で扱っている行列の行数が解説のものと1違ったので、少し違うことしているみたいです。

H - Histogram

 解説放送を見てAC。

・まずAでソート
・愚直なDPを書く
・式の形を見ると累積和が使えそう
・累積和を取ってまとめるとConvex Hull Trickが使える

 という流れ。難しいけれど、典型的な処理を繰り返せば解けるという意味で、解けなくてはいけない問題だと思う。

 式を見ても累積和に気付けなかったこと、Convex Hull Trick (CHT)の具体的な処理を忘れていたことは反省。ただ、Convex Hull Trickの書き方は結構使い回せるようなので、使うと分かったら以前の提出を参考にするようにしたい。
 今回の提出やDPまとめコンテストZの提出で、最小値の場合を書いている。
 ライブラリ化するのも有りか。

2022年1月9日日曜日

AtCoder Beginner Contest 234

 Gを除く七完。Hは嘘かと思いつつ投げたが、実際は正しい解法だったよう。

コンテスト後のツイート

G - Divide a Sequence

 解説AC。
 二乗のDPにはでき、式を書いてみると、maxとminは分割できることには気付けた。あとはなんらかの方法で高速化するのだろう、とは思ったが、stackを使った高速化は思いつかなかった。

 もらうDPで書いたとき、DP[i]の更新で必要なのは、各jについて、j~iについての最大値とDP[j]の値。
 この「j~iについての最大値」という配列は、jについて単調減少になっているため、そこに一つ要素xを付け加えたとき、変更されるのは後ろいくつかがxになる、というだけである。

 なので、[最大値, 最大値*DP[i]]というのをstackに突っ込んで置き、そこに新たに加わる要素xがstackの最後の要素より小さければただ付け加える。大きければ、最大値がxより小さいものたちについてmergeし、差分計算をしていけば良い。

 stackによる高速化は定石の一つなので、思いつかなかったのは反省。

 

2022年1月8日土曜日

yukicoder contest 326

 Dまで四完。

コンテスト後のツイート

No.1803 Remainder of Sum

 解説AC。
 初手で実験し、それを元に、MをNとの大小で場合分けするという方針はあっていたのだが、その後が詰められなかった。
 $M\leq N$のときの立式で間違っていたのは良くない。
 また、最後1とつないで辻褄合わせをするんだろうとは思ったのに、なぜかそれは大きい数字で行う気がして、2~$M-N$という小さい方で行うと思わなかった。

 最小全域木を作る、という気持ちになれなかったのが良くなかった気もするので、アルゴリズムの手法をちゃんと抑えるのが大事かね。

No.1804 Intersection of LIS

 解説AC(あまり考えずに解説を見た)。

 なるほど。
 共通部分を考えるとき、最大と最小をまず考える(今回は、辞書順最大・辞書順最小)のは定番ですね。
 一度それを考えてみるのは大切だし、証明できなくてもこれを投げてみよう、くらいのことはしても良かったか。

2022年1月7日金曜日

パナソニックプログラミングコンテスト2021(AtCoder Beginner Contest 231)

 Fまで六完。

コンテスト後のツイート

G - Balls in Boxes

 解説放送を見てAC。

 この問題ブログ内の記事)の類題だったが、身に着いていなかった。配り方に帰着するというのは覚えていたのだけど、実際にどうやるのかが難しい。

 他にも、これこれが類題だった。

 積の和を求めるのはなかなか難しくて、配り方へ帰着するしかない(ことが多い)、ということは頭に入っているのだけど、実際に解こうとすると頭がこんがらがってしまう。
 今納得できているけど、次回出たとき解けるかはあまり自信ないなぁ……。

H - Minimum Coloring

 解説放送を見てAC。

 フローを使いそう、とはコンテスト中も分かったが、その後のグラフの構築は大変。「容量下限付き最小費用流」のグラフの構築の仕方は勉強になった。とはいえ、しっくりきたかというとそこまでいっていないのが難しい……。一応納得したつもりではあるのだが。
 snukeさんのブログ記事にも大体同じ内容があるので、分からなくなったときはここも参考にしたい。

 なお、自分が元々持っていた最小費用流ライブラリだとTLEしてしまったので、少しだけ高速化した(それでもギリギリだった)。
 他の方のライブラリと同じことをしているつもりなのだけど、まだ若干遅いのは何故だろう。

2022年1月5日水曜日

AtCoder Beginner Contest 233

 Fまで六完。

コンテスト後のツイート

G - Strongest Takahashi

 解説放送を見てAC。
 全然DPを考えなかった。「行か列かで分割して良い」ということに気付くかどうか、というどちらかというと発想の問題ですね。

 Codeforcesで既出で、以前コンテストに参加していたものの未ACの問題でした。今回ACできて良かった。

Ex - Manhattan Christmas Tree

 解説放送を見てAC。並列二分探索に関するアルメリアさんの解説も参考にしました。
 「並列二分探索」というのは、何か自分の知らない特別な手法なのかと思っていたのですが、並列に二分探索するだけでしたね。怯える必要なかった。

 ただ、放送を見てしばらく、なんで並列でできるのか分からず困りました。分かってしまえば当たり前なんですが。
 最初理解できなかったのは、「答を決め打って二分探索」、という意識があったせいかな……。今回のような問題だと、データ構造を使い回して並列化できるのですね。

 各クエリごとに二分探索はできるけど、あまり賢い方法はなさそうなときは、並列二分探索を疑おう。

2022年1月4日火曜日

M-SOLUTIONS プロコンオープン2021(AtCoder Beginner Contest 232)

 Fまで六完。

コンテスト後のツイート

G - Modulo Shortest Path

 解説放送を見てAC。

 snukeさんも解説中に言っていたけど、私がコンテスト中に考えたのもフローだった。「フローが上手くいかない」と気付かないと厳しい。、そう気付けるようになるためには、もっとフローの練習を積まないといけないか。

 上手くグラフを作ればダイクストラでいけそう、と気付くためには、制約に注目するのが重要。「$A_i, B_i < M$」の制約の意味(和が2*Mを超えない!)に気付けば思いついてもおかしくないかな、と思う。
 

H - King's Tour

 一応自力AC。

 コンテスト中に考えたことは、
・(a, b)を通らないように周囲を一列、もしくは一行ずつ埋めていく。
・(a, b)からマンハッタン距離が遠いところを優先して通るように埋めていく。

 の二つ。

 一番目、二番目の片方ずつだと半分程度WAになったが、二つを組み合わせた(一個目で作った答えの途中から二番目を使う)らWAが二個まで減った。

 さらに、二番目で使っていた評価値「マンハッタン距離」を、max$($abs$(a-x),  $abs$(b-y))^2+$マンハッタン距離にしてみたらAC。

 Hackケースがあるかもしれないけど、それほど良い方法もない問題らしいので、まあ。

Hello 2022

 Dまで四完。なお、ツイートでは4WAと書いてますが、5WAだったようです。

コンテスト後のツイート

E. New School

 実装が間に合わなかったが、やり方はあっていた。

 人を削らないなら、グループ年齢の平均値が大きい順に、教師の年齢が大きいものを割り当てるのが最適。
 人を削ったら、そのソートした年齢順のリストの、あるindex xからindex yへうつる。その際、年齢平均のindexが[x, y]にあったグループのものは、一つプラス側かマイナス側にずれ、他は変わらない。
 なので、初期状態、一つプラス側にずれた場合、一つマイナス側にずれた場合、それぞれについて教師を割り振ることができるかを前計算しておく。そして、各人を削るごとに、そのグループがx→yへうつるかを二分探索により計算し、そのグループの判定および、他の判定を上記のようにすれば良い。

 私は、初期状態、プラス側、マイナス側についてセグ木を立てて実装したが、累積和でできる模様。
 また、ソートに小数を使う必要はなく、ceilさえ分かっていれば良い(教師の年齢は整数なので)というのは目から鱗だった。