题解 AT4535 【Slimes】

大家好,我是 CQ-C2024 蒟蒻 CJH。

这一道题目其实就是 P1775 石子合并(弱化版)

前置知识:区间 DP

状态设计

$dp_{i,j}$ 表示将区间 $[i,j]$ 合并所花费的最小代价。

边界条件

首先把 $1\le i \le n$ 时的 $dp_{i,i}$ 赋值为 $0$,因为自己不能合并自己。

剩下的因为要取得最小值,所以全部赋为极大值。

转移方程

在 $[i,j]$ 中枚举中间点 $k$,此时花费的成本为:$dp_{i,k}+dp_{k,j}+cost(i,j)$,这里的 $cost(i,j)$ 指合并两次的花费,其实就是 $\sum\limits_{x=i}^ja_x$,在去最小值即可。

所以转移方程就很显然了:

$$dp_{i,j}=\min(dp_{i,j},dp_{i,k}+dp_{k,j}+cost(i,j))$$

因为这里是某一段的和,所以可以用前缀和优化。

所求答案

根据状态可得,答案为 $dp_{1,n}$。

注意事项

变量要用 long long要不然就见祖宗

代码

//the code is from chenjh
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long LL;
int n;
LL a[404],b[404],dp[404][404];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%lld",&a[i]),
        b[i]=b[i-1]+a[i];//前缀和。
    memset(dp,0x3f,sizeof dp);//初始化为极大值。
    for(int i=1;i<=n;i++) dp[i][i]=0;
    for(int i=n-1;i>=1;i--)for(int j=i+1;j<=n;j++)for(int k=i;k<j;k++)//i 要倒着转移。
        dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+b[j]-b[i-1]);//状态转移。
    printf("%lld\n",dp[1][n]);
    return 0;
}

谢谢大家!

posted @ 2022-10-11 21:30  Chen_Jinhui  阅读(8)  评论(0)    收藏  举报  来源