Problem:


  MathJax.Hub.Config({ tex2jax: { inlineMath: [["$","$"], ["\\(","\\)"]], processEscapes: true }});

D - インビジブル

Problem Statement

あなたは友達と"インビジブル"というカードゲームを遊ぼうとしている．
このカードゲームでは，"得点カード"と"妨害カード"という2種類のカードを使う．
それぞれの得点カードには，正の値が書かれている．このカードゲームのルールは次の通りである．

 ゲームはプレイヤー1とプレイヤー2の2人のプレイヤーで行われる．ゲームはプレイヤー1のターンから始まる．

 場には，1つのスタックと2つのデッキがある．スタックは，2人のプレイヤーが置いたカードからなる．また，それぞれのプレイヤーが持つデッキはそのプレイヤーが持つ得点カードと妨害カードからなる．プレイヤーは自分，もしくは相手デッキのカードの順番をいつでも確認できる．ゲームの開始時点ではスタックには1枚もカードはない．

 2人のプレイヤーは交互に次の2つの行動のどちらかをちょうど1回行う．

 自分のデッキの一番上のカードをスタックの一番上に置く．ただし，この行動は自分のデッキにカードが1枚も存在しない時には行うことができない．

 自分のターンをパスする．

 プレイヤーがターンをパスした時，次の処理を行う．

 各プレイヤーは次の2つの条件を満たすスタック中のすべての得点カードを得る．得た得点カードは場から取り除かれる．

 自分がスタックにおいた得点カードである．

 相手が置いたどの妨害カードよりも上にある (スタック中に相手の妨害カードが存在しないとき，プレイヤーは自分がスタックに置いたすべてのカードを得る)．

 スタックのカードをすべて取り除く．

もしスタックにカードがない状態で両プレイヤーが連続してパスした場合，ゲームを終了する．
各プレイヤーの最終的なスコアは，各プレイヤーが得た得点カードに書かれた数の総和である．

各プレイヤーは，自分のスコアから相手のスコアを引いた値を最大化するために最適な行動をとる．
あなたの仕事は，与えられた各プレイヤーのデッキに対し，各プレイヤーが最適に行動したときのプレイヤー1のスコアとプレイヤー2のスコアの差を計算することである．

Input

入力は次のような形式の単一テストケースからなる．

$n$ $m$

$a_1$ $a_2$ $\dots$ $a_n$

$b_1$ $b_2$ $\dots$ $b_m$

1行目は山札の枚数を表す正の整数 $n$, $m$ ($1 \le n, m \le 50$) からなる．
2行目は $n$ 個の整数からなり，$a_i$ はプレイヤー1のデッキの上から $i$ 番目のカードを表す ($1 \le i \le n$)．$a_i$ は $1$ 以上，$1{,}000{,}000$ 以下，または $-1$ である．
3行目は $m$ 個の整数からなり，$b_j$ はプレイヤー2のデッキの上から $j$ 番目のカードを表す ($1 \le j \le m$)．$b_j$ は $1$ 以上，$1{,}000{,}000$ 以下，または $-1$ である．
$a_i$, $b_j$ が正の整数の時は得点カードを表し，$-1$ の時は妨害カードを表す．

Output

お互いのプレイヤーが最適に行動した時の (プレイヤー1のスコア) - (プレイヤー2のスコア) を出力せよ．

Sample Input 1

2 2
100 -1
200 300

Output for the Sample Input 1

-100

Sample Input 2

3 5
10 30 -1
-1 90 20 10 -1

Output for the Sample Input 2

0

Sample Input 3

4 5
15 20 10 30
50 30 10 20 25

Output for the Sample Input 3

-60


Sample input:
2 2
100 -1
200 300


Sample output:
-100

Submission status: Wrong Answer

Solution code:
#!/usr/bin/env python

from collections import deque
import itertools as it
import sys

sys.setrecursionlimit(1000000)

N, M = map(int, raw_input().split())

a = map(int, raw_input().split())
b = map(int, raw_input().split())
a = [0] + list(reversed(a))
b = [0] + list(reversed(b))
A = 1
B = -1

m = {}
m[(0, 0, A)] = 0
m[(0, 0, B)] = 0

def func(leftA, leftB, p):
    if leftA < 0 or leftB < 0:
        return 0
    if (leftA, leftB, p) in m:
        return m[(leftA, leftB, p)]
    ret = []
    for turn in [A, B]:
        idA = leftA
        idB = leftB
        scoreA = []
        scoreB = []
        sta_A = 0
        sta_B = 0
        print leftA, leftB, p
        while True:
            if idA < 0 or idB < 0:
                break
            if turn == A:
                if a[idA] == -1:
                    sta_B = 0
                else:
                    sta_A += a[idA]
                idA -= 1
                print a[idA]
                scoreB.append(func(idA, idB, B) + sta_A - sta_B)
            else:
                if b[idB] == -1:
                    sta_A = 0
                else:
                    sta_B += b[idB]
                idB -= 1
                print b[idB]
                scoreA.append(func(idA, idB, A) + sta_A - sta_B)
            turn *= -1
        score = 0
        print scoreA, scoreB, turn
        while True:
            if len(scoreA) == 0 and len(scoreB) == 0:
                break
            if turn == A:
                score = max(score, scoreA.pop())
            else:
                score = min(score, scoreB.pop())
            turn *= -1
        if p == A:
            m[(leftA, leftB, p)] = max(0, score)
        else:
            m[(leftA, leftB, p)] = min(0, score)
    ret.append(m[(leftA, leftB, p)])
    if(len(ret) == 1):
        return ret[0]
    if p == A:
        return max(ret[0], ret[1])
    else:
        return min(ret[0], ret[1])

func(N, M, A)
func(N, M, B)

for i in range(N):
    for j in range(M):
        for p in [A, B]:
            print m[(i, j, p)]

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():
    n,m = LI()
    a = LI()
    b = LI()
    fm = {}
    def f(ai,bi,pt,sa,sb,t):
        if pt > 2:
            return 0
        key = (ai,bi,pt,sa,sb,t)
        if key in fm:
            return fm[key]
        r = f(ai,bi,pt+1,0,0,not t) + sa - sb
        tr = 0
        if t:
            if ai < n:
                if a[ai] < 0:
                    tr = f(ai+1,bi,0,sa,0,not t)
                else:
                    tr = f(ai+1,bi,0,sa+a[ai],sb,not t)
                if r < tr:
                    r = tr
        else:
            if bi < m:
                if b[bi] < 0:
                    tr = f(ai,bi+1,0,0,sb,not t)
                else:
                    tr = f(ai,bi+1,0,sa,sb+b[bi],not t)
                if r > tr:
                    r = tr
        fm[key] = r
        return r

    r = f(0,0,0,0,0,True)
    return r


print(main())

Submission status: Accepted

Solution code:
n, m = map(int, input().split())
*A, = map(int, input().split())
*B, = map(int, input().split())

memo = {}
def dfs(p, q, s, t, turn, pss):
    if (p, q, s, t, turn, pss) in memo:
        return memo[p, q, s, t, turn, pss]
    if p == len(A) and q == len(B):
        return s-t

    res = 0
    if turn:
        # first
        if pss < 2:
            if s+t:
                res = (s - t) + dfs(p, q, 0, 0, 0, 0)
            else:
                res = dfs(p, q, 0, 0, 0, pss+1)
        else:
            return 0
        if p < len(A):
            if A[p] == -1:
                res = max(res, dfs(p+1, q, s, 0, 0, 0))
            else:
                res = max(res, dfs(p+1, q, s+A[p], t, 0, 0))
    else:
        # second
        if pss < 2:
            if s+t:
                res = (s - t) + dfs(p, q, 0, 0, 1, 0)
            else:
                res = dfs(p, q, 0, 0, 1, pss+1)
        else:
            return 0
        if q < len(B):
            if B[q] == -1:
                res = min(res, dfs(p, q+1, 0, t, 1, 0))
            else:
                res = min(res, dfs(p, q+1, s, t+B[q], 1, 0))
    memo[p, q, s, t, turn, pss] = res
    return res
print(dfs(0, 0, 0, 0, 1, 0))

Submission status: Accepted

Solution code:
n, m = [int(i) for i in input().split()]
A = [int(i) for i in input().split()]
B = [int(i) for i in input().split()]

memo = dict()

def calc(A, i):
    if A[i] != -1:
        return 0
    point = 0
    for j in range(i - 1, -1, -1):
        if A[j] == -1:
            break
        point += A[j]

    return point     
        

def dfs(a, b, skip, turn, a_stack, b_stack):
    key = (a, b, skip, turn, a_stack, b_stack)
    if key in memo:
        return memo[key]

    if skip == 3:
        return 0

    if turn % 2 == 0:
        memo[key] = dfs(a, b, skip + 1, (turn + 1) % 2, 0, 0) + a_stack - b_stack
        if len(A) == a:
            return memo[key]
        if A[a] == -1:
            b_stack = 0
        else:
            a_stack += A[a]
        memo[key] = max(memo[key], dfs(a + 1, b, 0, (turn + 1) % 2, a_stack, b_stack))
    
    else:
        memo[key] = dfs(a, b, skip + 1, (turn + 1) % 2, 0, 0) - b_stack + a_stack
        if len(B) == b:
            return memo[key]
        if B[b] == -1:
            a_stack = 0
        else:
            b_stack += B[b]
        memo[key] = min(memo[key], dfs(a, b + 1, 0, (turn + 1) % 2, a_stack, b_stack))

    return memo[key]

print(dfs(0, 0, 0, 0, 0, 0))