zoukankan      html  css  js  c++  java
  • [ HNOI 2014 ] 米特运输

    (\)

    (Description)


    给出一棵有根树,其中 (1) 号点是根节点,深度为 (1) 。每个点又有一个储存器,有各自的容量上限。

    每天 (1) 号点的储存器先清空,所有叶子节点全部充满能量。

    然后,深度为 (2) 的节点把 所有 储存的能量全部给根节点,然后,深度为 (3) 的节点把 所有 储存的能量给父节点,依次往下。

    运输过程中有几个要求:

    • 不能把父节点装入的能量超过限制,否则父节点爆炸
    • 必须把自己的所有能量给父节点
    • 每个节点的孩子给父亲的能量必须等量
    • 在每一层的传输完成后,父节点的那一层所存能量必须正好等于上界

    求把整个树形结构修改到满足上面的要求,最少需要修改多少个节点的容量上限。

    • (Nle5 imes 10^5)

    (\)

    (Solution)


    好一道语文题......

    总的限制其实就一个,要求调整后满足,对于每个节点,其容量上限等于子节点容量上限之和,且每个子节点容量上限相等。

    这道题的思路需要手玩.....

    (\)

    我们发现整颗树每一个节点的最终容量确定,只需要确定树中的任意一个节点的容量。

    因为节点之间的容量关系满足((cnt[x]) 表示节点 (x) 的子节点个数())

    [size[fa]=size[son] imes cnt[fa] , size[son]=frac{size[fa]}{cnt[fa]} ]

    显然确定一个点就能确定整棵树,同样的,我们也能得出一个结论,只要有一个节点容量相同,方案就相同

    (\)

    然后考虑如何快速表示出相同的方案,显然可以用同一个节点在这一方案里要求的权值表示,不妨选取根节点。

    然后我们的任务就是统计出每一个节点在容量上限不变的前提下,根节点的容量上限要变成什么。

    显然我们不再需要考虑子树内的点了,对于节点 (x) ,它不变的前提下根节点的容量就是

    [size[x] imes cnt[fa[x]] imes cnt[fa[fa[x]]] imes.... imes cnt[root] ]

    这个后缀我们可以在 (DFS) 的时候记录,根节点到当前节点路径上所有点的计数器之积。

    但是这个东西太大了,不太好记录,我们考虑 (Hash) 一下。其实还有更妙的方法。

    (\)

    我们知道对于对数有一个恒等式

    [log (A imes B imes... imes C)=log A+ log B+ ...+ log C ]

    然后我们可以通过取对数的方式来缩小数据范围,这样我们在 (DFS) 的时候只需要记录路径计数器取对数之和。

    然后将得到的答案排序,数字相同即是一个方案,代表在这个方案下这些点都不需要修改。

    统计最多的相同的数字有多少个,答案就是用 (N) 减掉它。

    (\)

    (Code)


    #include<cmath>
    #include<cstdio>
    #include<cctype>
    #include<cstdlib>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define N 500010
    #define R register
    #define gc getchar
    using namespace std;
    
    double ans[N];
    
    int n,m,tot,res,hd[N],val[N],cnt[N];
    
    struct edge{int to,nxt;}e[N<<1];
    
    inline void add(int u,int v){
      e[++tot].to=v; e[tot].nxt=hd[u]; hd[u]=tot;
    }
    
    void dfs1(int u,int fa){
      for(R int i=hd[u],v;i;i=e[i].nxt)
        if((v=e[i].to)!=fa){++cnt[u];dfs1(v,u);}
    }
    
    inline void dfs2(int u,int fa){
      for(R int i=hd[u],v;i;i=e[i].nxt)
        if((v=e[i].to)!=fa){ans[v]=ans[u]+log((double)cnt[u]);dfs2(v,u);}
    }
    
    inline int rd(){
      int x=0; bool f=0; char c=gc();
      while(!isdigit(c)){if(c=='-')f=1;c=gc();}
      while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=gc();}
      return f?-x:x;
    }
    
    int main(){
      n=rd();
      for(R int i=1;i<=n;++i) val[i]=rd();
      for(R int i=1,u,v;i<n;++i){
        u=rd(); v=rd(); add(u,v); add(v,u);
      }
      dfs1(1,0); ans[1]=log(1.0); dfs2(1,0);
      for(R int i=1;i<=n;++i) ans[i]+=log((double)val[i]);
      sort(ans+1,ans+1+n);
      for(R int i=1,tmp;i<=n;++i){
        tmp=1;
        while(fabs(ans[i+1]-ans[i])<=1e-8) ++tmp,++i;
        res=max(res,tmp);
      }
      printf("%d
    ",n-res);
      return 0;
    }
    
    
  • 相关阅读:
    git升级
    redis集群
    redis安装
    escript
    git搭建仓库与服务器
    svnsync
    post_commit.sh
    nvm安装和使用
    quartz 定时器
    Oracle flashback恢复误删的数据或表
  • 原文地址:https://www.cnblogs.com/SGCollin/p/9811485.html
Copyright © 2011-2022 走看看