かしのブログ

競技プログラミングとか

AtCoder AGC028 振り返り

2018.10.13 21:00~のAtCoder AGC028に参加
結果はABの2完。

A - Two Abbreviations

与えられた2つの文字列を元に、条件を満たす文字列の最小の長さを出力する問題。
条件は

  • 答えの文字列の長さ Lはそれぞれの文字列の長さの整数倍
  • 答えの文字列をN個に区切ったi個目の先頭は a_i
  • 答えの文字列をM個に区切ったi個目の先頭は b_i

と言い換えられる。

一つ目の条件より、LN、Mの最小公倍数とわかる。証明は以下、ただし文字列は0文字目からカウントする(問題文は1文字目からカウントしている)
ある答えの文字列の長さを nLとする。答えの文字列をN個に区切ったとき、そのi個目の先頭はa_iで、それぞれの文字列の長さはnの倍数になっている。同様に、答えの文字列をM個に区切ったとき、そのi個目の先頭はb_iで、それぞれの文字列の長さもnの倍数になっている。\frac{nL}{N}*i = \frac{nL}{M}*j (0 \le \frac{nL}{N}*i, \frac{nL}{M}*j < nL)ならばa_i = b_jなら有効な文字列である。ここで、LNとMの倍数なので、ある整数nで有効な文字列ならばn1以上の全ての整数に対して成り立つ。
以上

なるべく短い文字列を出力したいので答えは最小公倍数、もしくは無効な文字列の-1になる。
次に有効かどうかの判定をする。
\frac{L}{N}*i = \frac{L}{M}*j (0 \le \frac{L}{N}*i, \frac{L}{M}*j < L)ならばa_i = b_jならいいので、for文でチェックすればいい。無効な組み合わせを見つけたら-1、それがないなら最小公倍数が答え。(NとMが互いに素なら判定の必要はない)

https://beta.atcoder.jp/contests/agc028/submissions/3393088



B - Removing Blocks

全通りのシミュレーションをするとO(N!N^2)とかかかるので、効率化する必要がある。
具体的には、
   あるi個目のブロックのポイントが加算されるのは何回か
を求めて足し合わせる。
 i個目のブロックからn個離れたブロックが消えたときに、i個目のブロックのポイントが加算される必要十分条件はその間のブロックが全て消されてないこと。そこだけを抜き取って場合の数を数えるとn!。また、その他の順番はどうでもいいので、(N-n-1)!通り。ポイントに関係するn+1個のブロックと関係ないN-n-1のブロックの消す順番は独立していていいので、N-n箇所にn+1を重複込みで選択して挿入するので組み合わせ方は_{N-n}H_{n+1}。結局、n個離れたブロックが消えた時に加算する必要がある回数はc(n) = n!(N-n-1)!_{N-n}H_{n+1}
 x個目のブロックのポイントの加算回数は\sum_{k=0}^{N-1} c(|x-k|)。これを係数として、部分和を更新しながらa_i に足していくと答えが求められる。

https://beta.atcoder.jp/contests/agc028/submissions/3398384


一瞬DPかなあと思ったが方針はすぐにわかった。細かい計算を間違って時間を喰ってしまった。
解説の確率を使う方法も考えたけど、逆元使えば少数にならずに整数で可能になことに気づかなかった。かなC

感想

2完なのでぼちぼちだが、Bに時間がかかりすぎた。
C以降もなんのこっちゃだったので解説見てそのうち解く。