ABC178 D - Redistribution
備忘録
問題
回答
import sys, os, math, bisect, itertools, collections, heapq, queue, copy, array # from scipy.sparse.csgraph import csgraph_from_dense, floyd_warshall # from decimal import Decimal # from collections import defaultdict, deque sys.setrecursionlimit(10000000) ii = lambda: int(sys.stdin.buffer.readline().rstrip()) il = lambda: list(map(int, sys.stdin.buffer.readline().split())) fl = lambda: list(map(float, sys.stdin.buffer.readline().split())) iln = lambda n: [int(sys.stdin.buffer.readline().rstrip()) for _ in range(n)] iss = lambda: sys.stdin.buffer.readline().decode().rstrip() sl = lambda: list(map(str, sys.stdin.buffer.readline().decode().split())) isn = lambda n: [sys.stdin.buffer.readline().decode().rstrip() for _ in range(n)] lcm = lambda x, y: (x * y) // math.gcd(x, y) MOD = 10 ** 9 + 7 INF = float('inf') def main(): if os.getenv("LOCAL"): sys.stdin = open("input.txt", "r") S = ii() dp = [0] * (S + 1) dp[0] = 1 # 1 <= i <= Sの範囲を探索 for i in range(1, S + 1): # 0 <= j <= i - 3の範囲で、 # 間仕切りを置くことができる個数の合計を集計 if i > 2: dp[i] = sum(dp[0:i - 2]) dp[i] %= MOD print(dp[-1]) if __name__ == '__main__': main()
考え方
動的計画法で3以上の区間で
分けることが出来る回数を求める。
与えられるS
をS
個の並んだ石が存在すると考え、
並んだ石に対して、間仕切りを立てて3個以上連続するグループ分けするイメージで考えた。
例えばS = 7
のとき、石が7つ並んでいる。
〇 〇 〇 〇 〇 〇 〇
これに対して、先頭の隙間から間仕切りを立てることが出来るか否かを探索する。
例えば、隙間0
の位置は、
間仕切りを立てることができる。
│〇 〇 〇 〇 〇 〇 〇
となり、連続する石は全て3つ以上となる。
次に隙間1, 2
の位置は、
間仕切りを立てることができない。
〇 │ 〇 〇 〇 〇 〇 〇
や、〇 〇 │ 〇 〇 〇 〇 〇
は連続する石が3つ以下になるため。
次に隙間3
の位置について考える。
ここには間仕切りを立てることができる。
〇 〇 〇 │ 〇 〇 〇 〇
となり、分けられたグループは2つとなり、
連続する石はどちらも3つ以上になっている。
隙間4
についても、隙間3
とほぼ同一の形で間仕切りを立てることは可能。
最後に、隙間5, 6
について考えると、
この位置では、間仕切りを立てた後に、右のグループが必ず3つ以下なるため、探索は不要となる。
以上のようなイメージで、各隙間i
に対して、
その時点までに立てることができる間仕切りの総数を求めて回答をした。