ARC176

Bのみ1完。

A - 01 Matrix Again

例えば (i + j) % N < M を満たすマス(i, j)を1にすればどの行も列も和はMになる。あとはここから行や列を入れ替えて与えられたM個のマスをカバーすればいい。ここでは逆に与えられたマスたちを、M*Mのマスを斜めに半分に切って対角線上は加えた三角形に乗せることを考える。おそらくこれは達成できると思い、各行各列を与えられたマスの個数で降順ソートし左上に集める。それができたら集めたものを戻す変換で最初に作った例を出力する。最初、与えられたマスは出力しないと勘違いしていた。念のためにちゃんと与えられたマスを使っているか確認するコードを書いたところ、奏功してしまった。ソートだけでは達成できない。端から詰めていく。サンプルはよさそうだけどWA。証明してないのでしゃあない。

(追記)けっこう考えたけど他のアイデアを全く思いつかない。解説を見たら、あーもうやってられん。M*Mで考えてしまっていたんだなあ。そっち方向にバラバラにできるのか。ちょっと頭が悪すぎて考えようがなかった。最近、自分の実装力を信じずにARCを信じたほうがいい気はしているが、信じたところで思いつかないのでは意味がない。

B - Simple Math 4

何の性質の良さを使うのか迷う。2冪か、10や5で割ったあまりか、2^M-2^Kか。そういえばローリングハッシュで2^61-1で割ったあまりを求める方法をちゃんと追ってなかったなと。(NがM以上のとき)普通に2^Nから2^M-2^Kの倍数を引けるだけ引くことを考えると、2^N ≡ 2^(N-(M-K)) mod 2^M-2^K がわかる。M-KはMより小さいので、Nからそれを引けるだけ引いてM未満にするまでやって大丈夫。これは割り算でできる。これで、NがM未満の問題に帰着できたので、あとはatcoder::modintでmod 10で2冪を計算するだけ。WAで、言われてみれば2^N=2^M-2^Kとなるケースがあって(例えば2^8=2^9-2^8)、そのときは0を返すようにしてAC。これ気づくのは難しい。時間制限がある状況では仕方ないところ。

C - Max Permutation

グラフで考える。ある頂点から出ている辺のCたちを考える。同じ数が複数あるとき、その数はその頂点になければならない。その数はCたちの中で最小である必要がある。もう寝るので続きは明日書く。

(追記)日曜夜、気温のわりに寒く感じる気はしていたが、起きたら体が熱く微熱があって今日はずっとアニメを見るなどしていた(競プロみたいなことは頭が働かずできない)。夜になってようやくある程度の思考ができるようになってきたが、元の頭が悪いのでやはり大変だ。

コンテスト終了後、答えが0だとわかったときに0を出力して終了する関数を書き、順列の確定した値をセットする(違う値がセット済みだったら0通りを出力する)関数を書く。こういうの早めに整備するの大事。

各位置について確定した値を入れるvectorと何未満であることがわかっているというvector(最初は全部(0-indexedで)N)を持っておく。各頂点について、出てる辺のCの多重集合(2,2,2,3,4,6とか)が、最小のもの以外は全部1個ずつである必要がある。最小のもの以外は、相手がその値で確定。最小のものが複数あったら自分がその値で確定、1つだったら辺で結ばれた2頂点のどちらかがその値になるということで記録しておく。こいつらは、別の頂点を調べることで確定してしまうかもしれないのでそういう処理をする。するとおそらくこいつら(辺の集まり)は頂点を共有しない。つまり独立に考えられるので、どちらがそのCになるか勝手に決めてしまって答えを2倍すればいい。すると、確定した値と何未満であるという必要条件が残っておそらく十分条件にもなっている。ということで小さいほうから決めていけば通り数が求まる(典型だが、確定したものもあるのでやや難しい)。よくわからんので矛盾が生じたら(そういうことが起こりうるか自分にはわからないけど)すぐ0通りを返すようにどんどん処理を入れる。

なかなかサンプルが合わなかった。Cを0-indexedに直すの忘れていた。0未満からN未満まで表現するのでvectorの長さはN+1必要だった。確定した値がセット済みでも同じ数ならOKなのをうっかりした。辺の片側が決まってたときの処理でその値がCと等しいかで場合分けが必要だった。一応ACしたが、未証明とかいうレベルじゃない。通しただけ。解説見たらやはりもっとシンプルなんだな。

体調悪いのでAとCの実装はまたこんど。