题目链接:https://ac.nowcoder.com/acm/problem/210807
题意:有n个怪排成一排,你需要去消灭他们,消灭第i只怪的时候,会受到a[i]+b[i-1]+b[i+1]的伤害,消灭一只后,剩下的的会按原顺序重新战成一排,求最小承受伤害。
题解:区间dp.我们令dp[i][j]为消灭i-j的怪的最小伤害,那么就可以开始转移,最开始先处理好单独消灭每只怪的伤害(这个是固定的),然后在i-j间枚举断点来更新最小伤害。 (不明白具体实现可以看注释)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define paii pair<int,int>
#define fr first
#define sc second
const int maxn=505;
const int inf=0x3f3f3f3f;
int n,a[maxn],b[maxn];
int dp[maxn][maxn];
int main() {
    scanf("%d",&n);
    for (int i=1;i<=n;i++)scanf("%d",a+i);
    for (int i=1;i<=n;i++)scanf("%d",b+i);
    a[0]=a[n+1]=b[0]=b[n+1]=0;//可看成在0和n+1的地方都放一个a b为0的怪,方便后续转移
    for (int i=1;i<=500;i++)
        for (int j=1;j<=500;j++)
            if (j<i)dp[i][j]=0;//无意义的状态,但是在下面循环k的时候可能出现,初始化为0避免影响
            else
            dp[i][j]=inf;//初始化最大值
    for (int i=1;i<=n;i++)dp[i][i]=a[i]+b[i-1]+b[i+1];
    for (int len=2;len<=n;len++){//枚举区间长度,所以每次转移的子状态都已经计算好了
        for (int i=1;i<=n;i++){
            int j=i+len-1;
            if (j>n)continue;
            for (int k=i;k<=j;k++){
                dp[i][j]=min(dp[i][j],dp[i][k-1]+dp[k+1][j]+a[k]+b[i-1]+b[j+1]);
            }
        }
    }
    cout<<dp[1][n]<<endl;
    return 0;
}