AT274の技術だったりなかったり

あっとのTECH LOG

競プロのこととか技術のこととか。たまに日常を書きます。

JOI難易度6 ナイルドットコム

問題原文

https://www.ioi-jp.org/camp/2008/2008-sp-tasks/2008-sp_tr-day2_21.pdf

問題要旨

 D 日間、毎日  N 個の商品の中から1つを選んで購入する。
各商品の値段は毎日変動する。また、同じ商品を2日連続で買うと1割引で買え、3日以上連続で買うと3割引で買える。
払う金額を最小化せよ。

  •   2 \leq N \leq 3000
  •  2 \leq D \leq 365

解法

「定価で買った場合」「1割引で買った場合」「3割引で買った場合」のテーブルを持ってdpをする。
遷移は、

  • 定価で買うテーブル → 全テーブルの最小値 + 当該商品の値段
  • 1割引で買うテーブル → 定価で買うテーブルの同じ列 + 当該商品の値段 × 0.9
  • 3割引で買うテーブル → min(1割引で買うテーブルの同じ列, 3割引で買うテーブルの同じ列) + 当該商品の値段 × 0.7

になる。

実装

時間制限もメモリ制限も厳しいのでnumpyを使ってみた。
うまくかけてるのかもわからない。

import sys
import numpy as np
my_input = sys.stdin.readline

N, D = map(int, my_input().split())

BEST = 0
INF = 10 ** 9
dp1 = np.zeros(N)  # 普通に購入する
dp2 = np.full(N, INF)  # 2日続けて購入する
dp3 = np.full(N, INF)  # 3日以上続けて購入する

for i in range(D):
    items = np.array(list(map(int, my_input().split())))
    if i >= 2:
        dp3 = np.minimum(dp2, dp3) + items * 0.7

    if i >= 1:
        dp2 = dp1 + items * 0.9

    dp1 = items + BEST
    BEST = min(dp1.min(), dp2.min(), dp3.min())

print(int(BEST))

感想

いぇいいぇいいぇい。
ちょっと不思議な遷移だなと思いました。慣れていきたい。