Problem:


問題文

世の中の少女たちはキュゥべえと契約し願いを叶えてもらい，それとひきかえに魔法少女となる．使う魔法の形・効果は願いに強く影響を受ける．魔法少女さやかちゃんは最近キュゥべえと契約した新米魔法少女である．さやかの願いは「事故のため指が動かなくなり，音楽を演奏するのを諦めていた男の子を助けること」であったので，作る魔方陣は音符が輪の上に並んだ形をしている．

さやかは N 個の音符を持っており，それらを輪の上に並べることによって魔方陣を作る．音符をどのような順番で並べるかは彼女の自由である．魔方陣を作るために精神力が消費され，その量は音符の配置によって以下のように決まる．

まず， M 個の正の整数からなる音楽的美しさ S_1,\ ...,\ S_M が定められている，

各音符は音程を持っており，音程は 1 から M の整数 K_1,\ ...,\ K_N で表される．

音程が a,\ b\ (a≤b) であるような 2 つの音符の間の反発力とは， [(S_a\ +\ ...\ +\ S_b) / L] で定められる量である．ここで，L は入力で与えられる定数であり，実数 x に対して [x] は x を越えない最大の整数を表すものとする．

さやかの消費する精神力は，各2つの隣り合う音符 (N 組存在する) の間の反発力の合計値である．

例えば音楽的美しさがそれぞれ \{100,\ 200,\ 300,\ 400,\ 500\} で，音程が \{1,\ 3,\ 5,\ 4\} である音符をこの順番で並べて魔方陣を作った時，消費される精神力は 37\ (=[(100+200+300)/99]+[(300+400+500)/99]+[(500+400)/99]+[(400+300+200+100)/99]) となる．

使うべき音符の音程の組み合わせと各音程の音楽的美しさが与えられるので，消費される精神力の最小値を求めよ．

入力形式

入力は以下の形式で与えられる．

N\ M\ L\\
K_1\ K_2\ …\ K_N\\
S_1\ S_2\ …\ S_M

N はさやかの持っている音符の数，M は音楽的美しさの値の個数，L は反発力を定めるのに使われる定数である．

K_i は音符の音程を表し，S_j は音楽的美しさを表す．

出力形式

消費される精神力の最小値を 1 行に出力せよ．

制約

3 ≤ N ≤ 2,000

1 ≤ M ≤ 105

1 ≤ L ≤ 105

1 ≤ K_i ≤ M

1 ≤ S_j ≤ 105

入力値は全て整数である．

入出力例

入力例 1

4 5 99
1 4 5 3
100 200 300 400 500

出力例1

37

入力例 2

3 1 99
1 1 1
100

出力例 2

3

Problem Setter: Flat35

Sample input:
4 5 99
1 4 5 3
100 200 300 400 500


Sample output:
37

Submission status: Accepted

Solution code:
import sys
sys.setrecursionlimit(10**5)

def solve():
    readline = sys.stdin.readline
    write = sys.stdout.write

    N, M, L = map(int, readline().split())
    *K, = map(int, readline().split())
    *S, = map(int, readline().split())
    su = [0]*(M+1)
    r = 0
    for i in range(M):
        su[i+1] = r = r + S[i]
    K.sort()
    memo = [[-1]*N for i in range(N)]
    def calc(a, b):
        sa = K[a]; sb = K[b]
        if not sa < sb:
            sa, sb = sb, sa
        return (su[sb] - su[sa-1]) // L
    def dfs(i, a, b):
        if i == N:
            return calc(a, b)
        if memo[a][b] != -1:
            return memo[a][b]
        r = min(dfs(i+1, a, i) + calc(b, i), dfs(i+1, b, i) + calc(a, i))
        memo[a][b] = r
        return r
    write("%d\n" % dfs(1, 0, 0))
solve()

Submission status: Accepted

Solution code:
import math,string,itertools,fractions,heapq,collections,re,array,bisect,sys,random,time,copy,functools

sys.setrecursionlimit(10**7)
inf = 10**20
eps = 1.0 / 10**13
mod = 10**9+7
dd = [(-1,0),(0,1),(1,0),(0,-1)]
ddn = [(-1,0),(-1,1),(0,1),(1,1),(1,0),(1,-1),(0,-1),(-1,-1)]

def LI(): return [int(x) for x in sys.stdin.readline().split()]
def LI_(): return [int(x)-1 for x in sys.stdin.readline().split()]
def LF(): return [float(x) for x in sys.stdin.readline().split()]
def LS(): return sys.stdin.readline().split()
def I(): return int(sys.stdin.readline())
def F(): return float(sys.stdin.readline())
def S(): return input()
def pf(s): return print(s, flush=True)


def main():
    rr = []

    def f(n,m,l):
        k = sorted(LI())
        s = LI()
        wam = [0] * (m+1)
        for i in range(m):
            wam[i+1] = wam[i] + s[i]
        wa = [0] * n
        wb = [0] * n
        for i in range(n):
            wa[i] = wam[k[i]]
            wb[i] = wam[k[i]-1]

        fm = {}
        fm[(0,0)] = 0
        fm[(0,1)] = (wa[1] - wb[0]) // l
        def _f(i,j):
            key = (i,j)
            if key in fm:
                return fm[key]
            r = inf
            if i == j-1:
                for k in range(i):
                    t = _f(k,i) + (wa[j] - wb[k]) // l
                    if r > t:
                        r = t
            else:
                t = _f(i,j-1) + (wa[j] - wb[j-1]) // l
                if r > t:
                    r = t
            fm[key] = r
            return r

        r = inf
        for i in range(1,n-1):
            t = _f(i,n-1)
            u = (wa[n-1] - wb[i]) // l
            if r > t + u:
                r = t + u

        return r

    while 1:
        n,m,l = LI()
        if n == 0:
            break
        rr.append(f(n,m,l))
        break

    return '\n'.join(map(str, rr))


print(main())