ARC 064 F - Rotated Palindromes
問題
F: Rotated Palindromes - AtCoder Regular Contest 064 | AtCoder
問題概要
長さの数列としてあり得るものを全て用意する。ただし、は
- は回文(つまりとの逆順に並べたものは一致)
という条件を満たす。このようにして得られたに対して、「先頭の要素を末尾へ移動する」という操作を好きな回数行う。
これによって得られる最終的なとしてあり得るものが何通りあるかをで答えよ。
アイデア
例えば、数列の構成が長さ6で、abccbaのような数列だったとする。このときは、cyclic shiftにより構成される数列の種類は順に見ていくと
- abccba (回文)
- bccbaa
- ccbaab
- cbaabc (回文)
- baabcc
- aabccb
のようになっている。しかしながら、abababのような数列を考えるとabababとbababaの2種類しか現れないことがわかる。
このように数列内の最小周期によってその数列から生成される組み合わせの個数というのが変わってくる。そこで、この周期を全探索して、その結果を足し合わせることで全体を求めるということを考える。ただし、この全探索をする時は、「最短」周期を全探索するということを心に留めておく。
周期を全探索にするにあたって、この周期がの約数であることは明らか。この制約ならの約数の個数は多くても1500個程度であることがわかっているので、全探索できる。
さて、今周期をで固定する。さて、を全体で見て回文になっているのだから、この周期の数列も回文になっていなければおかしい(更にその周期の数列の中に未満の周期が存在していてはいけない)。さて、このことから、最低周期をに持つ数列として最初に設定できるものの個数をとすると、次の式が成り立つ:
回文なので、前半を自由に設定できるとして、ただしそこからそれ未満の周期が出来ている個数を引かなければいけないという式の形になっている。このしきにより、約数の個数の2乗のオーダーでこのDPを計算できる。
それができたら、個別に周期がある回文に対して、cyclic shiftした時に何種類の数列が生成されるかを掛け合わせたものを足し合わせることで最終的な答えが求められる。そこで、の偶奇によって生成される種類が変わってくる。まず、が奇数ならその時は中心の数の位置によって個全てが違うものであると区別がつくのでそのまま個になる。ただし、が偶数なら上でも見たようにcyclic shiftの途中でもう一度回文が出ていることになり、同じものを2回カウントしている事になっている。よってこの時は個がshiftによって生成されることになる。
実装(C++)
続きを読むCF 733 E - Sleep in Class
問題
問題概要
段の階段がある。各段は、下から順に番号がからまで付けられており、その各段にはup
かdown
かのどちらかが書かれており、その段にいるときに進む方向を示している。そして、そこから移動した瞬間に、その段の示す方向は反転する。
さて、次のような動作を考える:はじめに、あなたは段目の位置にいて、1秒に1回の移動を行う。そして、1段目にいるときにdown
するか段目にいるときにup
すると階段から落ちる。落ちるのにも1秒かかるとしたとき、落ちるまでにかかる時間を各について求めよ。いつまでも落ちることのない場合は、-1と答えよ。
アイデア
UとDの区間が交互に連続していると考えるとその区間はどんどんマージされていくので1つの立ち位置だけなら、シミュレーションによりで解けるように感じるが、今回はそれを全スタート位置についてやらなければいけないのでそれは厳しい。
あるスタート地点に立った時のことを考えてみると、そこから何回折り返しが発生するかというのはスタート位置よりも上にあるD
と下にあるU
の個数に依存してくることに気づく。
ということで、先頭からのU
の個数を累積和として配列に保存し、末尾からのD
の個数を累積和としてに記録することにする(この累積和に関して、自分自身のマスは考慮しないことにして、それぞれ自分より小さい範囲、自分より大きい範囲の位置を考える)。
次に、次のような配列とを考えてみる:
- : が常に
D
で不変であると仮定したときに位置からスタートして脱出までにかかる時間 - : が常に
U
で不変であると仮定したときに位置からスタートして脱出までにかかる時間
の方に注目してみると、まずは明らか。そして、との関係を考えてみる。すると、はの状況に比べてU
に遭遇したときに戻ってくるのに距離がだけ伸びていることになる。これを行き帰りで考慮しなければならないので1つのU
につき時間がだけ加算される。それと、はじめの一歩を考慮してという漸化式が立てられる。の方も同様にして、で初期化し、となる。
さて、階段の一番上の段から上に登って落ちるのか、一番下の段から下に降りて落ちるのかは、との大小関係から分かる。もしこの2つの値が等しい時には、スタート地点の方向を見れば、その方向に一致する。この関係性から落ちる方向は決まっているが、上からと下から、同時に落下すると仮定して、その合計の時間から実際には脱出出来ない方の時間の一部を引くという形でスタート位置が段目のときにかかる時間を求めていくことにする。このような方針にすることで、上で不自然な感じに設定したとが活かせる(を基準位置に区切ってかかる時間を考えることが出来るようになった)。
出口の方向にもよるが、からまたはを引くことになる(は出口とは反対方向で最終的に到達する位置)。また、ちょうど位置にいるときに反対で脱出されるわけではないので、数合わせをする必要もあるが、まずはについて考えてみる。
下から脱出するとすると、になる(はがU
なら1、D
なら0)。反対側で、最終的に到達する位置は、この折り返しの回数を考慮すると、配列にD
の現れる位置を上から順に保存しておくことにすれば、というということになる。を引けばよいわけだが、それだけでは足りない。余計にとの間を何回か往復していることになっているのでその分も引いて上げる必要がある。そして往復分を考えれば、ここで引くべきなのはとなる。これは、のこってる分だけ往復するのが第一項で、第二項が最後は結局反対側から出ていくので1回だけしか通過しないところがあるぶんを引いている。
上から脱出する時には、同様にの代わりに(U
の現れる位置を下から順に保存)を使って上と同じ考察をすればよい。