題目傳送門(內部題99)
輸入格式
第一行一個整數$n$,第二行$n$個整數$x_1\sim x_n$。
輸出格式
一行一個整數表示答案。
樣例
樣例輸入:
5
8 2 1 4 3
樣例輸出:
35
數據范圍與提示
樣例解釋:
數據范圍:
對於$10\%$的數據,$n\leqslant 10$。
對於$40\%$的數據,$n\leqslant 300$。
對於$70\%$的數據,$n\leqslant 2,000$。
對於$100\%$的數據,$n\leqslant 5,000,1\leqslant x_i\leqslant 10^9$。
提示:
二叉搜索樹或者是一棵空樹,或者是具有下列性質的二叉樹:若它的左子樹不空,則左子樹上所有結點的值均小於它的根結點的值;若它的右子樹不空,則右子樹上所有結點的值均大於它的根結點的值;它的左、右子樹也分別為二叉搜索樹。
題解
因為滿足二叉搜索樹的性質,所以一棵子樹里的點一定是連續的。
考慮$DP$,不妨一步一步來考慮,設$dp[x][l][r]$表示區間$[l,r]$的跟節點深度為$x$的最小代價。
轉移很簡單,無非就是枚舉$[l,r]$中哪個點做跟節點即可,時間復雜度是$\Theta(n^4)$的。
(考慮一個小優化:因為深度其實遠遠達不到$n$,也就是$\log n$多一點,所以直接掃到$10$左右就能拿到$40$分啦~)
考慮優化,發現深度每增加$1$,也就相當於又加了一個$\sum \limits_{i=l}^r x_i$,用前綴和優化就有了$\Theta(n^3)$的做法了。
接着優化,考慮貪心,因為決策點一定是單調的,做個解釋,假設現在要處理區間$[l,r]$,在處理它之前我們已經處理出來了$[l,r-1]$和$[l+1,r]$,並且知道了它們的最優決策點,那么$[l,r]$的最優決策點一定在$[l,r-1]$和$[l+1,r]$的最優決策點之間。
時間復雜度:$\Theta(n^2)$(均攤)。
期望得分:$100$分。
實際得分:$100$分。
代碼時刻
#include<bits/stdc++.h>
using namespace std;
int n;
long long v[5001],s[5001];
pair<long long,int> dp[5001][5001];
int main()
{
memset(dp,0x3f,sizeof(dp));
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&v[i]);
s[i]=s[i-1]+v[i];
dp[i][i]=make_pair(v[i],i);
}
for(int i=2;i<=n;i++)
{
for(int l=1;l<=n-i+1;l++)
{
int r=l+i-1;
for(int mid=dp[l][r-1].second;mid<=dp[l+1][r].second;mid++)
{
long long res=s[r]-s[l-1];
if(l<=mid-1)res+=dp[l][mid-1].first;
if(mid+1<=r)res+=dp[mid+1][r].first;
if(res<dp[l][r].first)dp[l][r]=make_pair(res,mid);
}
}
}
printf("%lld",dp[1][n]);
return 0;
}
rp++