题意:
给定圆周上的 n n n堆石子,每一堆有 w i w_{i} wi个石头,合并两堆的代价为两堆的石头总数之和,问合并所有堆为一堆的最小代价。
O ( n 2 ) O(n^2) O(n2)做法:
转移方程形如 d p [ i ] [ j ] = m i n ( d p [ i ] [ k ] , d p [ k + 1 ] [ j ] ) + w [ i ] [ j ] dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j] dp[i][j]=min(dp[i][k],dp[k+1][j])+w[i][j]的转移方程,可以用四边形不等式优化,将 O ( n 3 ) O(n^3) O(n3)的复杂度降为 O ( n 2 ) O(n^2) O(n2)。其中必须是 m i n min min, w [ i ] [ j ] w[i][j] w[i][j]表示处理区间为 [ i , j ] [i,j] [i,j]的贡献。
四边形不等式:
若 l ≤ l ′ ≤ r ′ ≤ r l \leq l' \leq r' \leq r l≤l′≤r′≤r,有 w [ l ′ ] [ r ′ ] ≤ w [ l ] [ r ] w[l'][r'] \leq w[l][r] w[l′][r′]≤w[l][r]或 w [ l ] [ r ′ ] + w [ l ′ ] [ r ] ≤ w [ l ] [ r ] + w [ l ′ ] [ r ′ ] w[l][r']+w[l'][r]\leq w[l][r]+w[l'][r'] w[l][r′]+w[l′][r]≤w[l][r]+w[l′][r′]成立,就有如下的不等式成立:
s [ l ] [ r − 1 ] < = s [ l ] [ r ] < = s [ l ] [ r + 1 ] s[l][r-1]<=s[l][r]<=s[l][r+1] s[l][r−1]<=s[l][r]<=s[l][r+1],其中 s [ l ] [ r ] s[l][r] s[l][r]表示为 [ l , r ] [l,r] [l,r]的最佳决策点,即使 d p [ l ] [ k ] + d p [ k + 1 ] [ j ] dp[l][k]+dp[k+1][j] dp[l][k]+dp[k+1][j]最小的 k k k
那么,我们计算 d p [ i ] [ j ] dp[i][j] dp[i][j]时,我们只需要在 [ s [ i ] [ j − 1 ] , s [ i + 1 ] [ j ] ] [s[i][j-1],s[i+1][j]] [s[i][j−1],s[i+1][j]]中枚举 k k k即可,假设我们在 j − i j-i j−i恒定的情况下枚举,也就是按顺序枚举 d p [ i ] [ j ] , d p [ i + 1 ] [ j + 1 ] , d p [ i + 2 ] [ j + 2 ] , . . . , d p [ n − ( j − i + 1 ) + 1 ] [ n ] dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n-(j-i+1)+1][n] dp[i][j],dp[i+1][j+1],dp[i+2][j+2],...,dp[n−(j−i+1)+1][n]
我们分别需要在
[ s [ i ] [ j − 1 ] , s [ i + 1 ] [ j ] ] [s[i][j-1],s[i+1][j]] [s[i][j−1],s[i+1][j]]
[ s [ i + 1 ] [ j ] , s [ i + 2 ] [ j + 1 ] ] [s[i+1][j],s[i+2][j+1]] [s[i+1][j],s[i+2][j+1]]
. . . . . ..... .....
[ s [ n − ( j − i + 1 ) + 1 ] [ n − 1 ] , s [ n − ( j − i + 1 ) + 1 − 1 ] [ n ] ] [s[n-(j-i+1)+1][n-1],s[n-(j-i+1)+1-1][n]] [s[n−(j−i+1)+1][n−1],s[n−(j−i+1)+1−1][n]]
中枚举 k k k,发现这些区间首尾相连,总长度为 s [ n − l + 2 ] [ n ] − s [ 1 ] [ l − 1 ] + n − l + 1 ≤ n + n = 2 n s[n-l+2][n]-s[1][l-1]+n-l+1\leq n+n=2n s[n−l+2][n]−s[1][l−1]+n−l+1≤n+n=2n
所以我们给定计算区间的长度,可以在 O ( n ) O(n) O(n)时间内计算完所有的这个长度的 d p dp dp值,枚举长度也是 O ( n ) O(n) O(n),总复杂度是 O ( n 2 ) O(n^2) O(n2)
最大值:
性质: d p [ i ] [ j ] dp[i][j] dp[i][j]的最大值总是在合并端点处取得,也就是 m a x ( d p [ i + 1 ] [ j ] , d p [ i ] [ j − 1 ] ) max(dp[i+1][j],dp[i][j-1]) max(dp[i+1][j],dp[i][j−1])
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int n,w[205],sum[205],dp[205][205],s[205][205];
int inf=0x3fffffff,ans=inf;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>w[i];
sum[i]=sum[i-1]+w[i];
s[i][i]=i;
}
for(int i=n+1;i<=2*n;i++)
{
w[i]=w[i-n];
s[i][i]=i;
sum[i]=sum[i-1]+w[i];
}
auto getvalue=[&](int l,int r)
{
return sum[r]-sum[l-1];
};
for(int i=1;i<=2*n;i++)
{
// for(int j=1;j<=2*n;j++) dp[i][j]=inf;
dp[i][i]=0;
}
for(int i=2*n-1;i>=1;i--)
for(int j=i+1;j<=2*n;j++) dp[i][j]=min(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
for(int i=1;i<=n;i++) ans=min(ans,dp[i][i+n-1]);
cout<<ans<<endl;
for(int i=2*n-1;i>=1;i--)
for(int j=i+1;j<=2*n;j++) dp[i][j]=max(dp[i+1][j],dp[i][j-1])+getvalue(i,j);
ans=-1;
for(int i=1;i<=n;i++) ans=max(ans,dp[i][i+n-1]);
cout<<ans;
return 0;
}