ABC268 C - Chinese Restaurant Python解答例
AtCoder Beginner Contest 268 C - Chinese RestaurantをPythonで解きます。
問題
問題文をAtCoderのページより引用します。
問題文
回転テーブルの周りに人
、人 0 、 1 、人 \ldots がこの順番で反時計回りに等間隔で並んでいます。また、人 N-1 の目の前には料理 i が置かれています。 p_i
あなたは次の操作を回以上何度でも行うことが出来ます。 0
- 回転テーブルを反時計回りに
周の 1 だけ回す。これによって、(この操作の直前に)人 \frac{1}{N} の目の前にあった料理は人 i の目の前に移動する。 (i+1) \bmod N 操作を完了させた後において、人
は料理 i が人 i 、人 (i-1) \bmod N 、人 i のいずれかの目の前に置かれていると喜びます。 (i+1) \bmod N
喜ぶ人数の最大値を求めてください。制約
3 \leq N \leq 2 \times 10^5 0 \leq p_i \leq N-1 ならば i \neq j p_i \neq p_j - 入力はすべて整数
p_i を人i の元に持っていくには何回操作が必要か?
料理説明の便宜上、人
- 人
は料理i が人i の目の前に置かれていると喜ぶ(i - 1) \mod N 料理\rightarrow が人i の左隣にあるとき喜ぶi - 人
は料理i が人i の目の前に置かれていると喜ぶi 料理\rightarrow が人i の正面にあるとき喜ぶi - 人
は料理i が人i の目の前に置かれていると喜ぶ(i + 1) \mod N 料理\rightarrow が人i の右隣にあるとき喜ぶi
まず、問題の中で定義されている操作の回数は0以上
この範囲の回数だけ操作を行う場合、料理
これを踏まえて、人
これはそれぞれ以下のように計算できます。
- 左隣に持っていくための回数:
(N - p_i + i - 1) \mod N - 正面に持っていくための回数:
(N - p_i + i) \mod N - 右隣に持っていくための回数:
(N - p_i + i + 1) \mod N
操作回数を求める式の求め方
求める操作回数を
料理
-
を人0の正面まで運ぶp_i - そこから人
の正面まで運ぶi
1.を達成するために必要な操作回数を
そこから人
従って、必要な操作回数は
尚、
左隣と右隣については正面についての式にそれぞれ
これらの回数だけ操作を行ったときだけ、人
操作を
人
すなわち、
全ての
実装例
Pythonによる実装例を以下に示します。
from typing import *
def main():
# 入力受け取り
N: int = int(input())
P: List[int] = list(map(int, input().split()))
# 操作をk回行ったときの喜ぶ人数の合計を表す配列
C: List[int] = [0] * N
# 全ての人iについて計算する
for i in range(N):
# 料理p_iが人iの左隣に来るような回数だけ操作を行うと、人iが喜ぶのでCが1増える
C[(N - P[i] + i - 1) % N] += 1
# 料理p_iが人iの正面に来るような回数だけ操作を行うと、人iが喜ぶのでCが1増える
C[(N - P[i] + i) % N] += 1
# 料理p_iが人iの右隣に来るような回数だけ操作を行うと、人iが喜ぶのでCが1増える
C[(N - P[i] + i + 1) % N] += 1
# 最大値を出力する
print(max(C))
if __name__ == "__main__":
main()
実際の提出はこちら。
ABCのC問題までは全探索が視野に入るっていう通説が以前あった気がするんですが、とうとうそれが通用しなくなって来つつあることを実感しています。
Discussion