2020年10月4日日曜日

Hokkaido University Programming Contest 2019 Day 2 D: Two Colors Sort

 問題はこちら。 

 積み残していたこの問題をACしました。


 解説pdfの通り、蟻本で「個数制限付き部分和問題」と紹介されている問題に帰着できるのですが、bitsetによる高速化ができることもあり、計算量解析が話題になりました。(参考:noshi91さんの記事


 ……が、今試してみたところ、特に工夫せず、Pythonのbit演算で普通にDPすれば間に合いました! Pythonで2秒程度なので、十分速いですね。


 今は、Kiriさんのこんな記事もあり、自分も(単純なものなら)0と1のみのDPテーブルを一つの数を代用する方法に慣れてきたと思いますが、当時は分かってなかったんですね。

2020年10月2日金曜日

グラフの直径と半径

 九月からブログ再開すると言っていたのに、いつのまにか10月になってしまった。なんでもいいから書こう。(とはいえ、こんなので良いのかな……)

東京大学プログラミングコンテスト2013 C - 直径

 を解いたが、最初、WAを出してしまった。


 まず、答えを書く(解説pdf通りです)と、

・グラフの直径:出来上がるグラフ上で最も遠い2点間の距離

・グラフの中心: もっとも遠い頂点への距離がもっとも小さい頂点

・グラフの半径:グラフの中心から最も遠い頂点への距離

 としたとき、

・最大値:直径の和+1

・最小値:半径の和+1もしくは、元の直径のうち大きい方

 となる。


 そこまでは分かったのだけど、自分は、半径=(直径+1)/2(切り捨て)と勘違いした(これは木なら成り立つはず)ためWAを出してしまった。変な先入観を持つのは避けなければ。

 次のようなグラフを考えれば、これは成り立ちませんね。


 このグラフだと直径=2、半径=2となる模様。

2020年9月4日金曜日

九月

 八月はこのブログをサボってしまった(その間に、AtCoderでは青に落ちてしまった……)のですが、九月になったしぼちぼち復活させていくつもりです。

 今までのように、「復習が終わったら記事を書く」としていると、どんどん書くコンテストが溜まってしまうので、すぐに書けるものはすぐに書くなど、ちょっと変えていきたい。

2020年7月31日金曜日

yukicoder contest 242

 maspyさんの回ということでやる気はあったのに、不出来で残念。

コンテストへのリンク
コンテスト後のツイート

No.1017 Reiwa Sequence

 解説AC。
 鳩の巣原理を使うんだろうと思っても、使い方が意外と難しい。n個の要素を-1か+1を選ぶのは$2^n$通りなので早く発散しそう……と思えば、それらの和の値で抑えるのは自然なのだけれど。鳩の巣原理を使いなれていると思いつきやすいんだろうなぁ。

 その後の実装をどうするかも悩んだ。
 単純な$3^N$では間に合わないけど、半分全列挙するのは面倒だし……と。結局、解説の「計算方法(1)」の方法で実装したけど、この実装もちょっと思いつきにくい気がする。
 たとえば、indexの集合 S={1,2,4}, T={2,4,6,7}とで和が一致するとき、2,4という重複要素はどうするんだろう……と思ってしまった。この場合、同じ要素を足しても打ち消し合うのでそこは0にして、$A_1, -A_6,-A_7$が0になる。冷静に考えれば分かるけど……。

2020年7月29日水曜日

April Fools Day Contest 2020

 Codeforcesのエイプリルフールコンテストは、去年出たけど全然分からなくて辛かった記憶があった。それを考えれば今年は健闘したと思う。

コンテストへのリンク
コンテスト後のツイート

C. ...And after happily lived ever they

 題名の文法がおかしくて、"... and they lived happily ever after"の並び替えになっているというところに気付かなくちゃいけない。英語力の問題だけど、これが分からなかったのは情けない。
 その後、二進数にしたものを並び替えるパートも難しい気がするけど……。そこまで気付いてればできるものなのかな。たどり着いていないので何とも言えない。

D. Again?

 今解説読んだら、OEISはミスディレクションだったのですね。

E. Jordan Smiley

 ペイントに画像をコピーし、内側を黒で塗りつぶした後、Pythonで処理した。
 そのコードはこんな感じ。x=13.5というのは、切り取ったときの一マスの幅です。

from PIL import Image
import numpy as np

im = np.array(Image.open('jor.png'))

x=13.5
ANS=[[0]*64 for i in range(64)]

for i in range(64):
    for j in range(64):
        if (im[int(i*x+x/2)][int(j*x+x/2)]==[0,0,0]).all():
            ANS[i][j]=0
        else:
            ANS[i][j]=1

yukicoder April Fool Contest 2020

 エイプリルフールコンテストらしい問題と、普通の問題があった……くらいの感想しかないなぁ、と問題を見直していたらとんでもないことに気付いた。

コンテストへのリンク

No.3063 幅優先探索

 壁を通っても良かったらしいです。
 コンテスト中、このことに気付いてなかったのに一発で(一回TLEは出してるけど)ACしている!

 ということは実装を間違っていて、「壁はいけない」という条件を書かずにBFSしたということで……えーっと。
 かなり恥ずかしいミスですが、それでACになってしまうと気付かないですね。

 全然普通の問題じゃなかった!

No.3070 ソラニン

 これが解けなかったのは悔しい。
 検索して片方は見つけていたのだけど、fとg二つがあるということは、片方が「イイネ」で片方が「RT」だと思い込んで分からなくなってしまった。
 思い込みはよくない。



Codeforces Round #630 (Div. 2)

 Eまで解いた。Fはあまり考えなかったよう。

コンテストへのリンク
コンテスト後のツイート

D. Walk on Matrix

  "bitwise AND"の演算では、0を作るのは簡単だし、桁が定まっているなら二進数表示で1111111という形の数とかけても値が変わらない。
 それを考えれば、0とkを作ろう、とするのは自然だと思う。

E. Height All the Same

 偶奇だけ考えれば良い問題であることは、実験すれば分かる。

 n*mが奇数のときはどのような場合でも構成できるが、n*mが偶数のときは、最初に置かれた個数が偶数個でなければ上手くいかない。その場合の数は大体半分に思えるけど、筋の良い証明方法が分からなかった。

 うーん、ただ、公式解説も結構技巧的だった。
 $k=R-L$として、(座標を適切に順序つけて)k個積み重なっていない最初の座標を xor 1する。そうすると、偶奇が変わるので、条件を満たすものと条件を満たさないもののペアができる。ただし、kが偶数のときは、条件を満たす方が一つ余る。だから、答えは、全体の半分か、半分+1になる、というもの。

 技巧的ではあるけれど、「ペアを作る」という考え方も、「xor 1を取ってペアにする」という考え方も重要なものではある。

 この問題についていえば、「直感的に半分になりそう」で答えを導ければ良いと思うけど、この証明方法も扱えるようになりたい。

F. Independent Set

 公式解説を読んで方針を理解してAC。
 木DP……と言われて木DPが何かをすぐ思い出せなかったのはまずい。根から葉の方向にDPを更新していく気がして、分岐でどうするんだろう……と思ってしまった。最近、全方位木DPの問題は何度か見たけど、木DPの問題を見ていなかった。
 葉から根に向けてDPを更新していくのですね。

 今回は、nodeと、そのnodeから根に向かうedgeの組について、「色を塗るかどうか」「誘導部分グラフを構成するときに使うかどうか」で場合分けして、この四通りのDPテーブルを埋めていけばOK。
 図を描いて落ち着いて考えれば遷移が分かりました。

G. No Monotone Triples

 アルメリアさんの解説記事を読んで解説AC。

 解かれている人数も少ないし公式解説も長いしで、普段なら手を出さないのですが、アルメリアさんが記事を書いている問題はACしないと! と思って頑張りました。

 解説を理解するのはそれほど難しくない(これは、アルメリアさんの記事が図も入っていて丁寧だ、ということも大きいですが)けれど、自力で思いつくのは難しいタイプの問題だと思います。そして、実装が大変……。

 解説記事を読んで方針は分かったのですが、二分探索が必要なのか? BITが必要なのか? あたりで戸惑いました。
 そのあたりは今の自分の力だと実際に実装してみないと分からないですね。使わないで書けるのでは? と思って実装してみたら上手く書けず、解説記事のやり方に落ち着く、というのを繰り返しました。

 厳密には、「長さ3の場合」は二分探索もBITもなしでやれますが、「長さ4の場合」は二分探索やBITとBIT上の二分探索が(自分の考えた限りでは)必要そうです。長さ3の場合での二分探索を使うなくしたらTLEが取れ、PyPyでもACできました。

 アルメリアさんの記事では長さ3の場合でもBIT等を使っていますが、長さ4での説明をスムーズにするためにそういう書き方にしているんだと思います。
 問題への理解が深まるにつれ、解説記事(とその実装方法)の評価が高くなっていった……というのは良い解説だという証拠ですね。