【ybtoj 高效进阶 5.2】 【区间DP】 石子合并
题目
解题思路
设f[l][r]为合并区间l~r的最小得分
设h[l][r]为合并区间l~r的最大得分
sum维护前缀和
因为是一个环将序列倍长处理
求一个区间l~r的得分
枚举一个k(l<k<=r)作为断点
f[l][r]=min(f[l][k-1]+f[k][r])+sum[r]-sum[l-1]
h[l][r]=max(h[l][k-1]+h[k][r])+sum[r]-sum[l-1]
注意要先做小区间
代码
#include<iostream>
#include<cstdio>
using namespace std;
const int inf=0x7ffffff;
int n,ans=inf,da,a[1010],sum[1010],f[1010][1010],h[1010][1010];
int main()
{
scanf("%d",&n);
for (int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
a[i+n]=a[i];
}
for (int i=1;i<=2*n;i++)
for (int j=1;j<=2*n;j++)
if (i==j) f[i][j]=0;
else f[i][j]=inf;
for (int i=1;i<=2*n;i++)
sum[i]=sum[i-1]+a[i];
for (int c=2;c<=n;c++) //枚举长度
for (int l=1;l+c-1<=2*n;l++) //枚举l
{
int r=l+c-1;
for (int i=l+1;i<=r;i++) //枚举断点
{
f[l][r]=min(f[l][r],f[l][i-1]+f[i][r]);
h[l][r]=max(h[l][r],h[l][i-1]+h[i][r]);
}
f[l][r]+=sum[r]-sum[l-1];
h[l][r]+=sum[r]-sum[l-1];
}
for (int i=1;i<=n;i++)
{
da=max(da,h[i][i+n-1]);
ans=min(ans,f[i][i+n-1]);
}
printf("%d\n%d",ans,da);
return 0;
}