zoukankan      html  css  js  c++  java
  • [BZOJ 3573][Hnoi2014]米特运输(乱搞)

    Description

    米特是D星球上一种非常神秘的物质,蕴含着巨大的能量。在以米特为主要能源的D星上,这种米特能源的运输和储
    存一直是一个大问题。D星上有N个城市,我们将其顺序编号为1到N,1号城市为首都。这N个城市由N-1条单向高速
    通道连接起来,构成一棵以1号城市(首部)为根的树,高速通道的方向由树中的儿子指向父亲。树按深度分层:
    根结点深度为0,属于第1层;根结点的子节点深度为1,属于第2层;依此类推,深度为i的结点属于第i+l层。建好
    高速通道之后,D星人开始考虑如何具体地储存和传输米特资源。由于发展程度不同,每个城市储存米特的能力不
    尽相同,其中第i个城市建有一个容量为A[i]的米特储存器。这个米特储存器除了具有储存的功能,还具有自动收
    集米特的能力。如果到了晚上六点,有某个储存器处于未满的状态,它就会自动收集大气中蕴含的米特能源,在早
    上六点之前就能收集满;但是,只有在储存器完全空的状态下启动自动收集程序才是安全的,未满而又非空时启动
    可能有安全隐患。早上六点到七点间,根节点城市(1号城市)会将其储存器里的米特消耗殆尽。根节点不会自动
    搜集米特,它只接受子节点传输来的米特。早上七点,城市之间启动米特传输过程,传输过程逐层递进:先是第2
    层节点城市向第1层(根节点城市,即1号城市)传输,直到第1层的储存器满或第2层的储存器全为空;然后是第3
    层向第2层传输,直到对于第2层的每个节点,其储存器满或其予节点(位于第3层)的储存器全为空;依此类推,
    直到最后一层传输完成。传输过程一定会在晚上六点前完成。
    由于技术原因,运输方案需要满足以下条件:
    (1)不能让某个储存器到了晚上六点传输结束时还处于非空但又未满的状态,这个时候储存器仍然会启动自动收集
    米特的程序,而给已经储存有米特的储存器启动收集程序可能导致危险,也就是说要让储存器到了晚上六点时要么
    空要么满;
    (2)关于首都——即1号城市的特殊情况,  每天早上六点到七点间1号城市中的米特储存器里的米特会自动被消耗
    殆尽,即运输方案不需要考虑首都的米特怎么运走;
    (3)除了1号城市,每个节点必须在其子节点城市向它运输米特之前将这座城市的米特储存器中原本存有的米特全部
    运出去给父节点,不允许储存器中残存的米特与外来的米特发生混合;
    (4)运向某一个城市的若干个来源的米特数量必须完全相同,不然,这些来源不同的米特按不同比例混合之后可能
    发生危险。
    现在D星人已经建立好高速通道,每个城市也有了一定储存容量的米特储存器。为了满足上面的限制条件,可能需
    要重建一些城市中的米特储存器。你可以,也只能,将某一座城市(包括首都)中原来存在的米特储存器摧毁,再
    新建一座任意容量的新的米特储存器,其容量可以是小数(在输入数据中,储存器原始容量是正整数,但重建后可
    以是小数),不能是负数或零,使得需要被重建的米特储存器的数目尽量少。

    Solution

    这个题的确很难…读懂

    语文水平越来越差了

    看了样例应该有点提示,其实就是要每个父节点u容量为子节点容量的d[u](子节点个数)倍

    也就是说,确定了任一点的容量,整棵树的容量都是确定的

    我们要做的是看确定哪一点需要的改动最少,就是看最多有多少个点确定的是相同的树(可以通过“只要节点1的容量是相同的树就是相同的”判断)

    t[i]:确定点i后节点1的容量

    因为数据很大,所以用到log(a*b)=log(a)+log(b)转换成log加法计算

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<queue> 
    #define eps 1e-9
    #define MAXN 500005
    #define INF 0x3f3f3f3f
    #define Max(a,b) (a>b?a:b)
    using namespace std;
    int n,a[MAXN],d[MAXN],head[MAXN],cnt=0; 
    double s[MAXN],t[MAXN];
    struct Node{
        int next,to;
    }Edges[MAXN*2];
    int dcmp(double x)
    {
        if(fabs(x)<eps)return 0;
        return x>0?1:-1;
    }
    void addedge(int u,int v)
    {
        Edges[++cnt].next=head[u];
        head[u]=cnt;
        Edges[cnt].to=v;
    }
    int read()
    {
        int x=0,f=1;char c=getchar();
        while(c<'0'||c>'9'){
            if(f=='-')f=-1;c=getchar();
        }
        while(c>='0'&&c<='9'){
            x=x*10+c-'0';c=getchar();
        }
        return x*f;
    }
    void get_s(int u,int f)
    {
        for(int i=head[u];~i;i=Edges[i].next)
        {
            int v=Edges[i].to;
            if(v==f)continue;
            s[v]=s[u]+log(d[u]);
            get_s(v,u);
        }
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;i++)
        a[i]=read();
        memset(head,-1,sizeof(head));
        memset(d,-1,sizeof(d));
        d[1]=0;
        for(int i=1;i<n;i++)
        {
            int a=read(),b=read();
            addedge(a,b);
            addedge(b,a);
            d[a]++;d[b]++;
        }
        s[1]=log(1);get_s(1,0);
        for(int i=1;i<=n;i++)
        t[i]=log(a[i])+s[i];
        sort(t+1,t+1+n);
        int ans=0,cnt=1;
        for(int i=2;i<=n;i++)
        {
            if(!dcmp(t[i]-t[i-1]))
            cnt++;
            else ans=Max(ans,cnt),cnt=1;
        }
        ans=Max(ans,cnt); 
        printf("%d
    ",n-ans);
        return 0;
    } 
  • 相关阅读:
    List注意点【修改】
    最近遇到的笔试面试题(3)
    关于阅读
    各种语言
    最近遇到的笔试面试题(2)
    最近遇到的笔试面试题(1)
    5自由落体运动
    4 1000以内完数
    3水仙花数
    判断101-200之间的素数
  • 原文地址:https://www.cnblogs.com/Zars19/p/6701724.html
Copyright © 2011-2022 走看看