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

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

ABC156 - E - Roaming

atcoder.jp

概要

n個の1~nまで番号がついてる部屋があって、それぞれ1人ずついる。ある部屋にいる一人が別の部屋へと行く行動をアクションと呼ぶ。
アクションがちょうどk回行われたときに、それぞれの部屋にいる人の数の組み合わせの数を10^9+7で割ったあまりで答えよ。

制約: 3 <= n <= 2 * 10^5, 2 <= k <= 10^9

ACするまで

1. kがやたらと大きいので、本当にk回シッカリ動かす必要があるのか?
2. ないです。(n, 0, 0, ..., 0)のようなパターンを作るのに最大でn - 1回しかかからないので、あまり大きい場合は何人かの人が部屋A->部屋B->部屋Aのように、反復運動をやればよさそう。
3. 動かす回数kを固定して、考えてみる。->わからないな


4. 0にする部屋の数を固定してみる。
5. そうすると、残りの部屋で和がnになるように、部屋の人数を振り分けることになる。
6. 丁寧に組み合わせを考えて、AC!

考察

for me:
今回の問題の敗因としては、最初に決める方針が間違ったせいできれいに詰められなかったことであるが、その根底には、一度決めた方針を考え直しづらいことが根底にあると思う。その原因は、数学力(特に組み合わせについて)に自信がないため、どの方針が正解なのかがわからないのが原因だと思う。この休みの間に、組み合わせについて特訓しようと思う。

a回動かしてたどり着ける盤面!とやろうとすると、次のような条件を満たすものを数え上げることになる。
 x_1+x_2+..x_n=n, 0 \leq x_iで、ちょうどa回の移動後。
ぼくにはa回移動後を上のような数式で表す方法は知らない


Point
DPじゃなくて数学系でやる組み合わせ問題は、とにかく固定する要素を挙げて、それを確かな数学力のもとで実行可能かを確かめる。

今回の場合は、「 x_iのうち0と等しい個数」を考える。
0の個数に関しては、最大ではn-1個((n, 0, ..., 0)を作るとき)である。
0の個数をa個とすると、0でない要素はn - a個存在することになる。それらは、n - a個の0でない要素の並び方は、
 x_1+x_2+...+x_{n-a}=n, x_i \ leq 1を満たすような (x_1, x_2, ..., x_{n-a})の組み合わせの数と同じ(重複組み合わせ)。
また、今回は0個であるものがa個存在するので、次のように考えると答えが見える。


n個のならんでる部屋のうちに、a個の部屋を選んで0人部屋だとして、残ったn - a個の部屋に、先ほど計算した重複組み合わせをそのまま該当させる。

数学力、いや組み合わせ力がある人はたぶんこれをそれはそうと思うのだが、そう思えるように一杯問題を解いていかないと。

これらの考察から、aを固定すればその時場合の数は {}_n \mathrm{C} _a * {}_{n-i} \mathrm{H} _nとなるので、これを0 <= a <= n - 1で集計すればよい。

ACソースコード
Submission #10293437 - AtCoder Beginner Contest 156

一言

なし。

まとめ


Point
DPじゃなくて数学系でやる組み合わせ問題は、とにかく固定する要素を挙げて、それを確かな数学力のもとで実行可能かを確かめる。