• [BZOJ1564][NOI2009]二叉查找树 树形dp 区间dp


    1564: [NOI2009]二叉查找树

    Time Limit: 10 Sec  Memory Limit: 64 MB
    Submit: 879  Solved: 612
    [Submit][Status][Discuss]

    Description

    Input

    Output

    只有一个数字,即你所能得到的整棵树的访问代价与额外修改代价之和的最小值。

    Sample Input

    4 10
    1 2 3 4
    1 2 3 4
    1 2 3 4

    Sample Output

    29

    HINT

    输入的原图是左图,它的访问代价是1×1+2×2+3×3+4×4=30。最佳的修改方案是把输入中的第3个结点的权值改成0,得到右图,访问代价是1×2+2×3+3×1+4×2=19,加上额外修改代价10,一共是29。

    Source

    观察到这就是一个treap。(其实没什么卵用)

    设sum为访问频率的前缀和。

    考虑dp,设f[w][i][j]表示从i到j组成根节点为原权值第w小之后的点的最小总代价。

    第一位从原来权值最大的点开始枚举w。

    之后两维枚举i,j。

    下一维枚举分割点d。

    分两种情况讨论:

    1.若修改点d的权值,那么f[w][i][j]=min(f[w][i][j],f[w][i][d-1]+f[w][d+1][to]+sum[to]-sum[i-1]+k);

    2.若不修改点d的权值,那么点d的权值要大于m,f[w][i][j]=min(f[w][i][j],f[t[d].a][i][d-1]+f[t[d].a][d+1][to]+sum[to]-sum[i-1]);

    ans=f[1][1][n]

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<cstdlib>
     5 #include<cmath>
     6 #include<algorithm>
     7 #define maxn 80
     8 using namespace std;
     9 int read() {
    10     int x=0,f=1;char ch=getchar();
    11     for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    12     for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    13     return x*f;
    14 }
    15 int n,k;
    16 struct data {
    17     int v,a,p;
    18 }t[maxn];
    19 bool cmp1(data t1,data t2) {return t1.a<t2.a;}
    20 bool cmp2(data t1,data t2) {return t1.v<t2.v;}
    21 int sum[maxn];
    22 int f[maxn][maxn][maxn];
    23 int main() {
    24     n=read();k=read();
    25     for(int i=1;i<=n;i++) t[i].v=read();
    26     for(int i=1;i<=n;i++) t[i].a=read();
    27     for(int i=1;i<=n;i++) t[i].p=read();
    28     sort(t+1,t+n+1,cmp1);
    29     for(int i=1;i<=n;i++) t[i].a=i;
    30     sort(t+1,t+n+1,cmp2);
    31     for(int i=1;i<=n;i++) sum[i]=sum[i-1]+t[i].p;
    32     for(int i=1;i<=n;i++)
    33         for(int j=1;j<=n;j++)
    34             if(t[i].a>=j) f[j][i][i]=t[i].p;
    35             else f[j][i][i]=t[i].p+k;
    36     for(int w=n;w>=1;w--) {
    37         for(int j=1;j<=n;j++) {
    38             for(int i=1;i+j<=n;i++) {
    39                 int to=i+j;
    40                 int tmp=2147483647;
    41                 for(int d=i;d<=to;d++) {
    42                     if(t[d].a>=w) tmp=min(tmp,f[t[d].a][i][d-1]+f[t[d].a][d+1][to]+sum[to]-sum[i-1]);
    43                     tmp=min(tmp,f[w][i][d-1]+f[w][d+1][to]+sum[to]-sum[i-1]+k);
    44                 }
    45                 f[w][i][to]=tmp;
    46             }
    47         }
    48     }
    49     printf("%d",f[1][1][n]);
    50 }
    View Code
    O(∩_∩)O~ (*^__^*) 嘻嘻…… O(∩_∩)O哈哈~
  • 相关阅读:
    Title提示样式修改
    列表查询数据交互简写形式
    cookie 一次性弹窗
    postman 使用 设置
    idea window mac安装
    在线校验格式化工具
    bootstrap下拉列表多选组件
    kaiguan
    5个数组Array方法: indexOf、filter、forEach、map、reduce使用实例
    对js里bind函数的理解
  • 原文地址:https://www.cnblogs.com/wls001/p/8058249.html
Copyright © 2020-2023  润新知