题目链接:https://loj.ac/problem/10147
解题思路
石子合并是区间合并很经典的题目了,本题既要找最大得分,也要找最小得分。并且石堆是在一个环上。如果我们将环分成n条链的话,时间复杂度是O(n^4)的。还有一种更好的方法,我们知道分成n条链分别dp的话,会计算很多重复的部分,因此我们完全可以充分利用这些重复的部分。我们将这条链延长2倍,扩展成2n-1堆。an+i对应ai,例如an+1=a1。此时再用区间dp,就可以在O(4n^3)的时间复杂度内完成。
AC代码
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=205;
const ll inf=(1ll<<62);
int n;
ll a[N<<1];
ll sum[N<<1];
ll dp_ma[N<<1][N<<1];
ll dp_mi[N<<1][N<<1];
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%lld",&a[i]);
a[n+i]=a[i];
}
for(int i=1;i<(n<<1);++i)
{
sum[i]=sum[i-1]+a[i];
dp_ma[i][i]=dp_mi[i][i]=0;
}
for(int len=2;len<=n;++len)
{
for(int i=1;i<(n<<1);++i)
{
int j=i+len-1;
if(j>=(n<<1))
break;
dp_ma[i][j]=0;
dp_mi[i][j]=inf;
for(int k=i;k<j;++k)
{
dp_ma[i][j]=max(dp_ma[i][j],dp_ma[i][k]+dp_ma[k+1][j]);
dp_mi[i][j]=min(dp_mi[i][j],dp_mi[i][k]+dp_mi[k+1][j]);
}
dp_ma[i][j]+=sum[j]-sum[i-1];
dp_mi[i][j]+=sum[j]-sum[i-1];
}
}
ll ma=0,mi=inf;
//cout<<inf<<endl;
for(int i=1;i<n;++i)
{
ma=max(ma,dp_ma[i][n+i-1]);
mi=min(mi,dp_mi[i][n+i-1]);
}
printf("%lld\n%lld\n",mi,ma);
return 0;
}