您的位置:首页 > 其它

【BZOJ1564】[NOI2009]二叉查找树【区间DP】

2016-04-26 15:21 288 查看
【题目链接】
这是一棵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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: