zoukankan      html  css  js  c++  java
  • [NOI2009]二叉查找树

    题面在这里

    题意

    给出一个(n)个节点的二叉排序树的原始数据值(d[i])、权值(v[i])和访问频度(s[i]),你可以根据需要把结点的权值改为任何实数,但每次修改你会付出(k)的额外修改代价,且修改后所有结点的权值必须仍保持互不相同。
    求整棵树的访问代价与额外修改代价的最小和。

    数据范围

    [nle 70,1le kle 3*10^7 ]

    sol

    根据最优二叉查找树的性质,考虑区间DP。
    如果设(f[i][j])表示仅考虑区间([i,j])内的节点所能得到的最小代价
    那么有转移方程

    [f[i][j]=min_{k=i}^{j}{f[i][p-1]+f[p+1][j]+sum_{l=i}^{j}{s[l]}+[(min_{l=i}^{j}{v[l]})==v[p]] imes k} ]

    (定义(f[x][x-1]=0))
    时间复杂度为(O(n^3))似乎太优秀了哈
    交上去后惊喜地发现只有(30').....

    因为我们不仅需要考虑每一段区间合并成一棵二叉树后的最小代价,
    还需要关注其节点在不同权值情况下的最小代价
    因为节点的代价会影响到后面的决策,使得设置的状态不满足最优子结构

    考虑节点作为当前树根被迫需要改变权值的情况只受到其子树权值最小值的影响(这段话很长,请多读几遍)因此多加一维表示区间内节点的最小值时的子问题

    即设(f[i][j][k])表示仅考虑区间([i,j])内的节点,
    使得当前所有节点的权值在离散化后都不小于(k)所能得到的最小代价

    那么决策便是改变权值(区间内有节点权值比当前枚举到的节点的权值要小)或者不改变权值(区间内所有节点权值都小于枚举到的节点的权值);
    转移方程在之前的方程中多加一维即可
    时间复杂度为(O(n^4))

    代码

    #include<bits/stdc++.h>
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<iomanip>
    #include<cstring>
    #include<complex>
    #include<vector>
    #include<cstdio>
    #include<string>
    #include<bitset>
    #include<cmath>
    #include<queue>
    #include<stack>
    #include<map>
    #include<set>
    #define mp make_pair
    #define pb push_back
    #define RG register
    #define il inline
    using namespace std;
    typedef unsigned long long ull;
    typedef vector<int>VI;
    typedef long long ll;
    typedef double dd;
    const dd eps=1e-10;
    const int mod=1e8;
    const int N=75;
    il ll read(){
      RG ll data=0,w=1;RG char ch=getchar();
      while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();
      if(ch=='-')w=-1,ch=getchar();
      while(ch<='9'&&ch>='0')data=data*10+ch-48,ch=getchar();
      return data*w;
    }
    
    il void file(){
      freopen("a.in","r",stdin);
      freopen("a.out","w",stdout);
    }
    
    struct node{int data,val,times;}t[N];
    bool cmp(node a,node b){return a.data<b.data;}
    
    int n,k,s[N],m[N][N],f[N][N];
    
    int main()
    {
        n=read();k=read();
        for(RG int i=1;i<=n;i++)t[i].data=read();
        for(RG int i=1;i<=n;i++)t[i].val=read();
        for(RG int i=1;i<=n;i++)t[i].times=read(),s[i]=s[i-1]+t[i].times;
        sort(t+1,t+n+1,cmp);
        
        memset(f,63,sizeof(f));
        for(RG int i=1;i<=n;i++)f[i][i]=t[i].times,m[i][i]=i;
        for(RG int i=1;i<=n+1;i++)f[i][i-1]=0;
        for(RG int l=2;l<=n;l++)
            for(RG int i=1;i<=n;i++)
                if(t[i+l-1].val<=t[m[i][i+l-2]].val)m[i][i+l-1]=i;
                else m[i][i+l-1]=m[i][i+l-2];
        
        for(RG int l=2;l<=n;l++)
            for(RG int i=1;i+l-1<=n;i++)
                for(RG int p=i;p<=i+l-1;p++)
                    f[i][l+i-1]=min(f[i][l+i-1],f[i][p-1]+f[p+1][i+l-1]+s[i+l-1]-s[i-1]+(m[i][l+i-1]==p?0:k));
        
        printf("%d
    ",f[1][n]);
                    
      return 0;
    }
    
    
  • 相关阅读:
    git push出现unpack failed: error Missing tree错误的解决方法
    Android N 分屏
    adb 查看最上层activity名字
    Ubuntu 切换JDK 版本
    Android的开机流程
    HTTP 协议中GET和POST到底有哪些区别(转)
    github爬虫100项目
    web攻击之xss(一)
    Kali-Dos洪水攻击之Hping3
    zipCrack-v1.1 工具介绍
  • 原文地址:https://www.cnblogs.com/cjfdf/p/8620075.html
Copyright © 2011-2022 走看看