[PYTHON] Ich persönlich habe den Erklärungsartikel des Abschnitts DP (Daruma drop) gekaut.

In dem Kommentarartikel des Abschnitts DP ( Referenz ) gab es einen Teil, den ich persönlich nicht verstehen konnte. Ich werde versuchen, es zu erklären, indem ich es persönlich kaue. (Möglicherweise liegt ein Fehler beim Verstehen vor ...)

Die folgenden zwei Punkte konnten nicht verstanden werden

    1. Warum auf der rechten Seite freigeben? Es ist in 2,2 Fälle unterteilt, aber gibt es noch andere Fälle?

1. 1. Warum die rechte Seite freigeben?

・ Weil der Index bei 0 beginnt ・ Wenn 0 <= l, r <n, können die folgenden Ausdrücke verwendet werden.

dp [l] [r]: = Anzahl der Blöcke, die im Intervall [l, r] entfernt werden können

・ Weil ich den Abschnittsunterteilungspunkt (Mitte im obigen Referenzartikel) als rekursiven Ausdruck verwenden möchte. Wenn der Ausdruck auf beiden Seiten geschlossen ist (dh das Intervall [l, r]), ist die Division wie folgt.

Teilen Sie den Abschnitt in [l, mid], [mid + 1, r]

Es ist in 2,2 Fälle unterteilt, aber gibt es noch andere Fälle?

Im Referenzartikel wurden die Fälle wie folgt aufgeteilt.

1. Ein Block von l und ein Block von r -1 können gepaart werden
2. Teilen Sie den Abschnitt in [l, mid), [mid, r)

In Fall 1 verschwinden alle Teile, die zwischen beiden Enden angeordnet sind, und die verbleibenden Enden verschwinden. Wie eine Kette von Puyopuyo. Fall 2 ist ein Fall, in dem die maximale Anzahl von Entfernungen für jedes Teil erhalten wird, indem es in zwei Teile geteilt wird.

Gibt es einen anderen Fall für meine Frage? Das ist. Ich habe den Grund für MECE in 2 Fällen nicht verstanden. Was ist zum Beispiel mit dem Fall, in dem der zwischen beiden Enden eingeklemmte Teil verschwindet und zwei übrig bleiben und die verbleibenden zwei zusammen mit beiden Enden verschwinden? (Fall A) Was ist mit dem Fall, in dem der zwischen beiden Enden eingeklemmte Teil verschwindet und einer übrig bleibt und der verbleibende Teil mit einem der beiden Enden verschwindet? (Fall B)

Als ich es in die Abbildung schrieb, stellte ich fest, dass es im zweiten Fall enthalten war. (Ich konnte nicht beweisen, dass es in zwei Fällen passt)

Fall A. ![1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694198/0c34b48b-23f9-5f91-7f4d-215ca4211f4a.png)ケースB![2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/694198/db829c87-6eeb-b861-8584-ec076353dd6c.png)
import sys

sys.setrecursionlimit(250000)
input = sys.stdin.readline
dp = []
w =[]

def rec(l,r):
    #Wenn es bereits durchsucht wurde, wird sein Wert zurückgegeben.
    if dp[l][r] >= 0:
        return dp[l][r]

    #0, da ein einzelner Fall nicht gelöscht werden kann
    if l == r:
        dp[l][r] = 0
        return 0

    #Bei durchgehenden Teilen
    if l + 1 == r:
        if abs(w[l] - w[r]) <= 1:
            dp[l][r] = 2
            return 2
        else:
            dp[l][r] = 0
            return 0

    res = 0

    #Fall 1 Alle zwischen beiden Enden eingeklemmten Teile verschwinden und die verbleibenden beiden Enden verschwinden
    if abs(w[l] - w[r]) <= 1 and rec(l+1, r-1) == (r - 1) - (l + 1) + 1:
        res =  (r - 1) - (l + 1) + 1 + 2
    else: #Fall 2 Der zwischen beiden Enden eingeklemmte Teil verschwindet nicht
        for mid in range(l,r):
            res = max(res, rec(l,mid)+rec(mid+1,r))

    dp[l][r]=res
    return res
def main():
    global w
    global dp
    n_list=[]
    w_list=[]

    while True:
        n = int(input())
        if n == 0 :
            break
        w_tmp = list(map(int, input().split()))
        n_list.append(n)
        w_list.append(w_tmp)

    for i in range(len(n_list)):
        dp = [[-1] * n_list[i] for j in range(n_list[i])]
        w = w_list[i]
        print(rec(0,n_list[i]-1))
main()