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

来源:互联网 发布:淘宝卖家评价回复模板 编辑:程序博客网 时间:2024/06/08 11:06
【题目链接】

这是一棵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;}


0 0
原创粉丝点击