题解 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;
}
谢谢大家!

浙公网安备 33010602011771号