这是一棵Treap,而且我们知道BST的中序遍历的数据值是递增的,那么我们按照数据值排个序,就得到中序遍历了。然后就变成区间DP啦。
设dp[l][r][m]表示,区间[l, r]的节点组成的树中的,根节点的权值≥m的最小代价。
然后枚举根节点转移。
(1)将根节点i的权值修改为m,有dp[l][r][m] = dp[l][i – 1][m] + dp[i + 1][r][m] + K
(2)根节点i的权值≥m时,dp[l][r][m] = dp[l][i – 1][i的权值 + 1] + dp[i + 1][r][i的权值 + 1]
求得dp[l][r][m]最小值后,再给dp[l][r][m]加上[l, r]每个节点的访问频度。
/* Pigonometry */
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 75;
const LL inf = 0x3f3f3f3f3f3f3f3f;
int n, K, tot, disc[maxn];
LL dp[maxn][maxn][maxn];
struct _data {
int val, w, fre;
bool operator < (const _data &x) const {
return val < x.val;
}
} A[maxn];
inline int iread() {
int f = 1, x = 0; char ch = getchar();
for(; ch < '0' || ch > '9'; ch = getchar()) f = ch == '-' ? -1 : 1;
for(; ch >= '0' && ch <= '9'; ch = getchar()) x = x * 10 + ch - '0';
return f * x;
}
inline int find(int x) {
int l = 1, r = tot;
while(l <= r) {
int mid = l + r >> 1;
if(disc[mid] < x) l = mid + 1;
else if(disc[mid] == x) return mid;
else r = mid - 1;
}
}
inline LL dfs(int l, int r, int lb) {
if(l > r) return 0;
if(~dp[l][r][lb]) return dp[l][r][lb];
LL res = inf;
for(int i = l; i <= r; i++) {
res = min(res, dfs(l, i - 1, lb) + dfs(i + 1, r, lb) + K);
if(A[i].w >= lb) res = min(res, dfs(l, i - 1, A[i].w + 1) + dfs(i + 1, r, A[i].w + 1));
}
res += A[r].fre - A[l - 1].fre;
return dp[l][r][lb] = res;
}
int main() {
n = iread(); K = iread();
for(int i = 1; i <= n; i++) A[i].val = iread();
for(int i = 1; i <= n; i++) disc[i] = A[i].w = iread();
for(int i = 1; i <= n; i++) A[i].fre = iread();
sort(A + 1, A + 1 + n);
sort(disc + 1, disc + 1 + n);
tot = unique(disc + 1, disc + 1 + n) - (disc + 1);
for(int i = 1; i <= n; i++) A[i].w = find(A[i].w), A[i].fre += A[i - 1].fre;
memset(dp, -1, sizeof(dp));
printf("%lld\n", dfs(1, n, 1));
return 0;
}