Senの競技プログラミング備忘録

こけた問題を自分用の解説で載せる。けんちょんさんのブログを目指したい。質的にも量的にも。こけた問題だけに限定するけど

Educational Codeforces Round 48 (Rated for Div. 2) - D. Vasya And The Matrix

codeforces.com

概要

n行m列の行列で、毎行のxorの結果はa[1~n]、毎列のxorの結果はb[1~m]として与えられる。これを満たす行列を存在するのならば、YESと答えて、1つ構築せよ。存在しないのならば、NOとだけ答えよ。

制約: 1 <= n, m <= 100, 0<= a[i], b[i] <= 10^9 出力する行列の各要素は2*10^9以下。

ACするまで

1. ずっと考えて、うまく1点だけピックアップするようにやろうとするも、厳しい。
2. 構築のテンプレとして、想定解がスカスカの疎行列であることがよくあるので、対角成分しかない行列を考える->むりぽ
3. 1h経って何も見えないので、ギブアップ


4. 解説解法、奇想天外ながらも確かに典型で疎行列を考えるパターンだった。(対角成分を詰めるパターンではないけど)。この解法を本記事の中では天才解法という。
5. さらに言うと、天才解法以外にも、凡人解法が存在していて、地道に桁ごと見ていくことで、構築できるみたい。
6. 両方ACした。

考察

天才解法

Are you a genuine genius? I'm fake!
天才にはこれが見えるそうですね。(終)

f:id:Sen_comp:20200319152946j:plain
(訂正)上の一番下にある式の左辺で、 a_1が抜けていました。すいません。

次回から天才になるための知見を抽出します。

行列構築の想定解の典型は、疎行列になる(ほとんどの成分はほかに影響を与えない0という単位元で埋め尽くされる)
その中で、答えに影響を与えるような値の置く場所としては、

今回は、1つの行と1つの列に詰め込んでみる、という方針があれば、少し手を動かせば、この解法にたどり着けるだろう。

ソースコード
Submission #73578416 - Codeforces

凡人解法

以下のtsubasaさんが書いたブログを大いに参考にしました。こちらも合わせてごらんください。
emtubasa.hateblo.jp

XORの問題なので、「困難は分割せよ」の通りに、


bit演算は、当然ながら桁ごとが独立して扱える!
という通りに、桁ごとに立ってるか、立ってないかを見ます。

構築可能条件は、天才解(公式解答)と同じです。(構築可能条件を確証があまり持てないながらも、意外には思いつくとは思う)現時点では、この構築可能条件は、「これを満たすならば構築不可能」とはまだ言い切れないので、必要条件にとどまっています。

ひとまず、行のXORと列のXORが一致しないのを除外してみます。

そうすると、下図のように、「(着目した桁において)bitが立ってる数の個数」が行と列において、かならず偶奇が一致するとわかります。(XORの偶奇を考えればわかる)

f:id:Sen_comp:20200319153007j:plain

さて、偶奇が一致した時に、うまく行列の成分に1を配置して、条件を満たす者が作れるのでしょうか?

奇数個一致する場合と、偶数個一致する場合と場合分けをして、奇数個の場合は簡単です。偶数個の場合は、様々な考え方がありますが(参考にしてもらったtsubasaさんは別のもっと実装が軽い方法でやっていました)、僕のこの方法が一番思いつきやすいのではないでしょうか?

奇数個は、着目してる成分の行も列もその桁で立っていたら、立てることにします。(最終的に、どの行も列も、奇数個立つので問題ない)
f:id:Sen_comp:20200319153020j:plain

ただし、0個立ってる場合は例外処理をしましょう。

f:id:Sen_comp:20200319153037j:plain

逆に、行と列で、その桁においての立ってるbit数の偶奇が一致しないのならば、どうがんばっても構築できません。

見ての通り、仮の判定条件とした(行のXORと列のXORが一致)もので、作れる、作れないがきれいに分かれています。よって、判定条件は必要十分であったとわかります。

ACソースコード
Submission #73589263 - Codeforces

一言

事の始まり。

ちなみに彼は見える側の人間です。
僕は見えるようになりました。