ABC140 D - Face Produces Unhappiness
問題原文
問題要旨
一列に 人の人が並んでおり、各人は右か左を向いている。どの人も、目の前の人と同じ方向を向いていれば幸福を感じる。
以下の操作を 回以上 回以下繰り返して、幸福な人の数を最大化せよ。
ある範囲の人の列を180度回転させる。(順番を反転させて、その後選んだ範囲の人の向きを逆にする。)
解法
操作がよくわからん
操作がややこしい。いろいろ実験して理解を深める。
例えば LLRR
を選ぶと、まず順番反転して RRLL
その後各人の向いている向きを逆にして、 LLRR
。あれ、元に戻った。
RLR
ならどうか。まず順番反転して RLR
その後各人の向いている向きを逆にして、 LRL
。少し変わった。
RLLLLLR
だと? → LRRRRL
となる。どうやら範囲内の幸福な人の人数は変わらないことがわかる。
操作で幸福な人はどう変わる
?
例えば LLRRRL
だと、 3文字目から5文字目(RRR
)に対して操作を行うと、 LLLLL
にできる。この操作で、幸福な人は2人増えた。
範囲内の幸福な人の人数は変わらない + 操作で基本2人幸福な人が増える ことがわかる。また、 LLLLL
の幸福度は4なので、最大の幸福度が であることもわかる。
どこを選んで反転させるべき?
LLLLRRRRLLLLRRRLLL
などがあれば、これは RRRR
と RRR
を選ぶべき。
RRRRLLLLRRRRLLLRRR
であれば、 LLLL
と LLL
。
RLRLRL
であれば、 R
の3つ or L
の3つ。
結局 L
or R
の塊を選べばいいことがわかる。
結論
何回幸福度を増やす操作ができるか → min(L
の塊の数, R
の塊の数)
1操作につき幸福度は何増えるか → 基本2(端っこの時だけ1)
幸福度の上限は
より、 min(最初の状態の幸福度 + min(min(L
の塊の数, R
の塊の数), K) × 2, N - 1 ) が答えになる。
実装
N, K = map(int, input().split()) S = input() ans = 0 for i in range(N): if S[i] == 'L': if i - 1 < 0: continue if S[i - 1] == 'L': ans += 1 else: if i + 1 >= N: continue if S[i + 1] == 'R': ans += 1 X = min(len([s for s in S.split('L') if s != '']), len([s for s in S.split('R') if s != ''])) ans += min(X, K) * 2 print(min(ans, N - 1))
感想
割と苦手だけど、普通にいい問題。
端っこの処理とかがめんどくさく感じるけど、 「答えの上限値を知っておくことで、無駄な場合わけが減らせる」 ことがあることをしっかり覚えておきたい。