zoukankan      html  css  js  c++  java
  • [BZOJ 3573] 米特运输

    Link:

    BZOJ 3573 传送门

    Solution:

    一道语文题

    转化后的题意就是使得每个节点的权值都等于 父亲节点的权值/儿子数 的最小操作数

    能发现一条重要的性质:只要一个节点确定,所有节点的权值都确定了

    于是我们只要枚举$1……n$每个节点权值不变,

    算出根节点$root$的权值出现过的最多次数$res$,用$n-res$即是结果

    但如果$O(n^2)$枚举不仅TLE,而且会爆精度

    于是我们将权值都用$log$来表示:

    (1)算出当根节点$root$为“单位一”:$log(1)$时,各个节点的权值$t_i$

    (2)对于节点$v$,$t_v*log(原权值)$就能算出此时根节点在$log$下的权值,接着统计即可

    Code:

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MAXN=5e5+10;
    const double eps=1e-6;
    double t[MAXN],top[MAXN];
    int n,dat[MAXN],siz[MAXN];
    vector<int> G[MAXN];
    
    void dfs(int x,int anc)
    {
        for(int i=0;i<G[x].size();i++)
        {
            int v=G[x][i];
            if(v==anc) continue;
            t[v]=t[x]+log(siz[x]);dfs(v,x);
        }
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&dat[i]);
        for(int i=1;i<n;i++)
        {
            int x,y;scanf("%d%d",&x,&y);
            G[x].push_back(y);G[y].push_back(x);
            siz[x]++;siz[y]++;
        }
        for(int i=2;i<=n;i++) siz[i]--;    
        
        t[1]=log(1);dfs(1,0);
        for(int i=1;i<=n;i++) top[i]=t[i]+log(dat[i]);
        sort(top+1,top+n+1);
        
        int res=0,cur=1;
        for(int i=2;i<=n;i++)
            if(top[i]-top[i-1]<eps) cur++;
            else res=max(res,cur),cur=1;
        res=max(res,cur);
        printf("%d",n-res); 
        return 0;
    }

    Review:

    1、出现只涉及比较,但不用输出确切值的高精度问题时,

    使用$log$或$hash$即可,不用高精度类

    2、“单位一”的使用

    这里的“单位一”用得很妙啊,

    如果每次只要乘上相应倍数即可$O(1)$得解,可以用“单位一”的思想先预处理

  • 相关阅读:
    状态模式
    $和@的特殊处理
    Windows服务调试状态下用Console启动
    AutoResetEvent
    await和async
    计算a,b,c的排列组合
    百度地图:通过经纬度获得位置信息和距离
    装饰模式
    vue+h-ui+layUI完成列表页及编辑页
    为什么memset不能将数组元素初始化为1?
  • 原文地址:https://www.cnblogs.com/newera/p/9121047.html
Copyright © 2011-2022 走看看