Python3で解く AtCoder Beginner Contest 174 D - Alter Altar
個存在する状態をを目指すようにして、それぞれの状態における最小の手数を数えて、全状態の中で最小値をみつければいい。状態をどう考えるか、その時の最小の手数はどう考えればいいかというのがポイント。
概要
- かと書かれた石が並んでいる。次の2つの行動が取れる。(1つで手数として+1)
- 石を2つ選んで位置を入れ替えられる。
- 石を1つ選んで色をからもしくは逆ができる。
- の左側にがない状態にしたい。
- 上記の状態を作るためにかかる最小の手数は?
解くときに考えた内容
- 全部WにするのがいいのかRのするのがいいのか、それともRRRWWWWのようにするのがいいのかは状況によってかわるため、取りうる状態の最小手数を考えなくてはいけない。
- たとえば、7文字あるとして 与えられた現状(とりあえずRWRWRWRとすると)から、以下の状態の全てを最小手数で目指す。
RWRWRWR → WWWWWWW RWRWRWR → RWWWWWW RWRWRWR → RRWWWWW ・・・・・・ RWRWRWR → RRRRRRW RWRWRWR → RRRRRRR
- 各状態の手数の中の最小値が条件を満たす最小値になる。
- ここで重要なのは、それぞれの状態というのは区切り(|)があるようなイメージで、|より右はW、左はRにするように行動する。
|RWRWRWR → WWWWWWW R|WRWRWR → RWWWWWW RW|RWRWR → RRWWWWW RWR|WRWR → RRRWWWW RWRW|RWR → RRRRWWW RWRWR|WR → RRRRRWW RWRWRW|R → RRRRRRW RWRWRWR| → RRRRRRR
- その時にかかる最小手数は、区切りよりも左側のの数を、区切りよりも右側のの数をとするとになる。理由は、区切りの左側と区切りの右側のかの大小によって、最小手数が変わるためで、以下のように考える。
- のとき、区切りの左側にあるをと入れ替えるので回。残りの区切りの右側にあるは個であるのでそれらを全部に変える。全部で回になる。
- のとき、区切りの左側にあるをと入れ替えるので回。残りの区切りの左側にあるは個であるのでそれらを全部に変える。全部で回になる。
- あとはこれを実装する。
- の初期値は0とする。
- 最初に与えられたを数えての初期値とする。
- あとは与えられる石の並びの一つ目からだったらとして、だったらとすれば、各区切りの状態のとなるので、最後の文字までやれば、区切りを一番最後の状態まで見たことになる。
反省点
ごちゃごちゃ、場合分けするのではなくて、目指す方向性を決めて、全部数えてから最小値を見つけるっていう流れにしなければいけなかった。
まぁむずいなぁ。。。問題を言い換えて、最小手数をともかく大きい方っていう形に変えられるかがポイントだった。
コード
n = int(input()) C = input() r_all = C.count('R') # CをRWRWRWRとした時に、 # どの状態にするのが最小手数かがわからないので全パターンである以下の状態における最小手数を計算する。 # ある場所を境に右側をW左側をRとするイメージ。 # |RWRWRWR→WWWWWWW # R|WRWRWR→RWWWWWW # RW|RWRWR→RRWWWWW # ....... # RWRWRW|R→RRRRRRW # RWRWRWR|→RRRRRRR # 最小手数をリストに入れておく。パターンはn+1 move = [0] * (n+1) # 実際の並びにおいて、|の左のW右のRの数をw, rとする # 初期値はw=0, r=CのうちRの数 w = 0 r = r_all # moveの初期値はすべてWを目指すので move[0] = max(0, r_all) # forで1文字ずつ見ていくのは区切りを一つずつずらしているイメージ # Cの文字をみてWならwを1増やしてRならrを1減らす # (区切りの左のWの数がwで右のRの数がrなので) for idx, c in enumerate(C): if c == 'W': w += 1 else: r -= 1 move[idx+1] = max(w, r) ans = min(move) print(ans)